联机测试方案

1. 系统概述

本方案设计基于 go-libp2p 的分布式工业配置与控制权同步系统的完整联机测试流程,覆盖编译构建、远程部署、功能测试、异常场景验证等全部环节。

核心定位: 这是一个”分布式配置 + 控制权系统”,而不是”数据同步系统”

  • Config → CRDT-like,最终一致性
  • Ownership → Lease,强约束
  • Runtime → Owner Only,单点主控

2. 测试环境准备

2.1 双节点拓扑

┌──────────────────────────┐         libp2p:4001         ┌────────────────────────────┐
│ 本机 (开发机)              │◄─────────────────────────►│ 远程 (root@192.168.3.230)   │
│                          │                           │                            │
│ OS: Windows/Linux        │       节点发现 + 配置同步    │ OS: Linux ARM64            │
│ 启动: go run cmd/main.go │                           │ 启动: systemctl edgex       │
│ 节点: NODE-1             │                           │ 节点: NODE-REMOTE           │
│ API: http://localhost:8082 │                         │ API: http://192.168.3.230:8082│
└──────────────────────────┘                           └────────────────────────────┘

2.2 环境要求

项目 本机 (开发机) 远程 (192.168.3.230)
操作系统 Windows/Linux/macOS Linux ARM64
Go 版本 1.21+ 无需(已编译为二进制)
Node.js 16+ (构建前端用) 无需
goreleaser 已安装 (goreleaser --version) 无需
SSH 密钥 可免密登录 root@192.168.3.230 接受 SSH 连接
防火墙 放行 4001/tcp 4001/udp 放行 4001/tcp 4001/udp 8082/tcp
依赖 无特殊要求 systemd, dpkg, curl

3. 编译与构建

3.1 方式一:本地开发运行(go run

适用于快速开发调试,版本信息为默认值 dev/unknown/unknown

# 1. 安装前端依赖并构建(首次或前端有变更时执行)
cd ui && npm install && npm run build && cd ..

# 2. 直接运行(开发模式,版本=dev)
go run cmd/main.go

# 3. 或指定 ldflags 注入真实版本信息
go run -ldflags="-X github.com/anviod/edgex/internal/model.Version=0.0.4 \
                 -X 'github.com/anviod/edgex/internal/model.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)' \
                 -X github.com/anviod/edgex/internal/model.CommitID=$(git rev-parse --short HEAD)" \
       cmd/main.go

验证本地启动成功

# 检查服务端口
curl -s http://localhost:8082/api/auth/system-info
# 预期返回:{"code":"0","data":{"name":"NODE-1","softVer":"dev","buildTime":"unknown","commitID":"unknown"}}

# 检查 libp2p 监听
netstat -an | grep 4001

3.2 方式二:goreleaser 构建多平台安装包

适用于正式版本构建,自动注入版本信息并生成所有平台的 .deb / .tar.gz

# 完整构建(构建前端 + 编译 Go + 打包所有平台)
goreleaser release --snapshot --clean --config .goreleaser.yml

构建流程详解

步骤 1: go mod tidy              # 整理依赖
步骤 2: npm run build (./ui)     # 构建 Vue 前端 → ui/dist/
步骤 3: GOOS/GOARCH 矩阵编译     # CGO_ENABLED=0,静态链接
        ├── linux/amd64
        ├── linux/arm64
        ├── linux/arm (ARMv7)
        ├── windows/amd64
        └── windows/arm64
步骤 4: ldflags 注入版本信息      # Version / BuildTime / CommitID
步骤 5: 打包 tar.gz               # 归档包(含 conf/ scripts/ ui/dist/)
步骤 6: 打包 .deb                 # dpkg 包(含 preinstall/postinstall/edgex.service)
步骤 7: SHA256SUMS                # 校验和文件

产物列表(在 dist/ 目录下):

dist/
├── edgex-v0.0.4-amd64.deb          # AMD64 deb 安装包
├── edgex-v0.0.4-arm64.deb          # ARM64 deb 安装包(远程节点使用)
├── edgex-v0.0.4-arm.deb            # ARMv7 deb 安装包
├── edgex-0.0.4-linux-amd64.tar.gz  # AMD64 归档
├── edgex-0.0.4-linux-arm64.tar.gz  # ARM64 归档
├── edgex-0.0.4-linux-arm.tar.gz    # ARMv7 归档
├── edgex-0.0.4-windows-amd64.tar.gz
├── edgex-0.0.4-windows-arm64.tar.gz
└── SHA256SUMS

构建后验证版本注入

# 解压本地对应架构的包,验证版本信息写入正确
tar -xzf dist/edgex-0.0.4-linux-amd64.tar.gz -C /tmp/edgex-test
/tmp/edgex-test/edgex --version 2>/dev/null || \
  strings /tmp/edgex-test/edgex | grep -E "^(0\.0\.[0-9]+|$(git rev-parse --short HEAD))"

4. 远程部署(deb 方式)

4.1 一键部署

# 语法: bash scripts/deploy-remote.sh <远程主机> <节点名称>
bash scripts/deploy-remote.sh root@192.168.3.230 NODE-REMOTE

4.2 部署流程详解

[步骤 1] 检查 SSH 连接
    ├── ssh -q root@192.168.3.230 "echo 'SSH连接正常'"
    └── 失败 → 终止部署,提示检查 SSH 密钥

[步骤 2] 检测远程架构
    ├── ssh root@192.168.3.230 "uname -m"
    ├── aarch64 → arm64
    ├── armv7l  → arm
    └── x86_64  → amd64

[步骤 3] 查找匹配的 .deb 包
    ├── ls dist/edgex-v*-arm64.deb | sort -V | tail -1
    └── 未找到 → 终止部署,提示先执行 goreleaser 构建

[步骤 4] SCP 传输安装包
    └── scp dist/edgex-v0.0.4-arm64.deb root@192.168.3.230:/tmp/

[步骤 5] 备份现有配置
    ├── cp -rf /usr/local/bin/edgex/data → /tmp/edgex_backup/
    └── cp -rf /usr/local/bin/edgex/config → /tmp/edgex_backup/

[步骤 6] 停止旧服务
    └── systemctl stop edgex

[步骤 7] 卸载旧版本
    └── apt remove -y edgex

[步骤 8] 安装新版本
    ├── dpkg -i /tmp/edgex-v0.0.4-arm64.deb
    └── 依赖缺失 → apt-get install -f -y 自动修复

[步骤 9] 配置节点名称
    └── sed -i "s/node_name:.*/node_name: NODE-REMOTE/" /usr/local/bin/edgex/config/sync.yaml

[步骤 10] 启动服务
    ├── systemctl daemon-reload
    ├── systemctl enable edgex
    └── systemctl start edgex

[步骤 11] 验证服务状态
    └── sleep 5 && systemctl is-active edgex → active

4.3 部署后验证

# 1. 服务状态
ssh root@192.168.3.230 "systemctl status edgex --no-pager"

# 2. API 可达性(含版本信息验证)
ssh root@192.168.3.230 "curl -s http://localhost:8082/api/auth/system-info | python3 -m json.tool"
# 预期返回:
# {
#   "code": "0",
#   "data": {
#     "name": "NODE-REMOTE",
#     "softVer": "0.0.4",
#     "buildTime": "2026-06-05T...",
#     "commitID": "efa219a"
#   }
# }

# 3. libp2p 端口监听
ssh root@192.168.3.230 "ss -tlnp | grep 4001"

# 4. 服务日志(检查是否有 libp2p 相关输出)
ssh root@192.168.3.230 "journalctl -u edgex -n 50 --no-pager"

4.4 手动部署(备用方式)

当脚本不可用时的手动部署流程:

# 1. 手动 SCP 传输
scp dist/edgex-v0.0.4-arm64.deb root@192.168.3.230:/tmp/

# 2. SSH 进去执行
ssh root@192.168.3.230

# 3. 备份配置
cp -rf /usr/local/bin/edgex/data /tmp/edgex_backup/ 2>/dev/null || true
cp -rf /usr/local/bin/edgex/config /tmp/edgex_backup/ 2>/dev/null || true

# 4. 停止并卸载
systemctl stop edgex 2>/dev/null || true
apt remove -y edgex 2>/dev/null || true

# 5. 安装
dpkg -i /tmp/edgex-v0.0.4-arm64.deb || apt-get install -f -y

# 6. 配置节点名
sed -i 's/node_name:.*/node_name: NODE-REMOTE/' /usr/local/bin/edgex/config/sync.yaml

# 7. 启用并启动
systemctl daemon-reload && systemctl enable edgex && systemctl start edgex

# 8. 退出 SSH
exit

5. 功能测试

测试原则:每个测试用例必须严格按照文档设计验证。测试执行顺序遵循依赖关系(先基础后高级)。

5.1 测试前置条件

执行所有测试前,确保:

# 本机确认
curl -s http://localhost:8082/api/auth/system-info  # NODE-1 在线

# 远程确认
curl -s http://192.168.3.230:8082/api/auth/system-info  # NODE-REMOTE 在线

5.2 测试用例:节点发现与加入(P0)

TC-01:mDNS 局域网自动发现

项目 内容
目标 验证两个节点通过 mDNS 互相发现
前置条件 NODE-1 (本机) 和 NODE-REMOTE (远程) 均已启动,同处 192.168.3.0/24 网段
测试步骤 1. 启动 NODE-1 的 go run cmd/main.go
2. 确认 NODE-REMOTE 已通过 systemctl 启动
3. 等待 30s(discovery_interval)
4. 调用 NODE-1 的集群 API
API 调用 GET http://localhost:8082/api/sync/peers
预期结果 返回的 peers 列表包含 NODE-REMOTE 的 PeerID,状态为 online
通过标准 peers 数量 ≥ 2,NODE-REMOTE 在线
失败排查 检查防火墙是否放行 4001/udp(mDNS);检查两台机器是否同一子网

TC-02:Bootstrap 静态发现

项目 内容
目标 验证通过 bootstrap_peers 配置的静态节点发现
前置条件 conf/sync-config.yaml 已配置 bootstrap_peers(含远程节点 PeerID)
测试步骤 1. 在远程节点临时禁用 mDNS
2. 重启 NODE-1
3. 等待连接建立
API 调用 GET http://localhost:8082/api/sync/peers
预期结果 NODE-1 通过静态种子发现并连接到 NODE-REMOTE
通过标准 NODE-REMOTE 出现在 peers 列表中

TC-03:新节点加入网络(全量同步)

项目 内容
目标 验证新节点加入后自动触发全量配置同步
前置条件 NODE-REMOTE 已有 3 个 channel、5 个 device、120 个 point 的配置
测试步骤 1. 启动 NODE-1(新节点)
2. NODE-1 发现 NODE-REMOTE
3. NODE-1 自动发起全量同步
API 调用 GET http://localhost:8082/api/sync/node/NODE-REMOTE/tree
预期结果 NODE-1 的配置树包含与 NODE-REMOTE 完全相同的 channel、device、point
通过标准 配置树节点数量和结构与 NODE-REMOTE 一致,所有 hash 匹配
一致性验证 GET http://localhost:8082/api/sync/consistencyoverall_status: "consistent"

5.3 测试用例:配置同步(P0)

TC-04:全量配置同步

项目 内容
目标 验证全量同步模式正确传输所有配置
前置条件 双节点在线,NODE-1 为新节点(配置为空或版本旧)
测试步骤 1. 触发 NODE-1 → NODE-REMOTE 的全量同步
API 调用 POST http://localhost:8082/api/sync/trigger {"mode":"full"}
预期结果 sync_status 返回 mode: "full", status: "completed"
一致性检查 两节点 channels.yaml 内容一致

TC-05:增量同步(Delta Sync)

项目 内容
目标 验证修改单个配置项后仅同步变更部分
前置条件 双节点同步已完成(一致状态)
测试步骤 1. 在 NODE-1 修改 channel modbus-1port 从 502 → 503
2. 等待 Announce 广播
3. NODE-REMOTE 检测 hash 不一致后拉取 delta
API 调用 NODE-REMOTE: GET /api/sync/node/NODE-1/diff
预期结果 diff 仅包含 channel.modbus-1.port: 502→503;不包含其他未变更的配置
通过标准 diff 列表精确对应变更项,无多余项,无遗漏
验证 NODE-REMOTE 的 channel modbus-1 port 变为 503

TC-06:点位级别同步

项目 内容
目标 验证最小粒度(单个 point)的同步能力
前置条件 双节点同步已完成,设备 PLC-01 含 point temp
测试步骤 1. 在 NODE-1 修改 PLC-01 的 point temp.scale0.11.0
2. 等待自动增量同步
API 调用 GET /api/sync/node/NODE-1/device/PLC-01/points
预期结果 NODE-REMOTE 上的 temp.scale 更新为 1.0;其他 point 不受影响
通过标准 只有一个 point 发生变更,其他 point 不变

5.4 测试用例:控制权管理(P0)

TC-07:Exclusive 设备 - 禁止接管

项目 内容
目标 验证 exclusive 模式设备不允许被其他节点接管
前置条件 NODE-1 拥有一个 Modbus RTU 设备(access_mode: exclusive),正在采集
测试步骤 1. NODE-REMOTE 尝试接管该设备
API 调用 POST http://192.168.3.230:8082/api/ownership/takeover {"device_id":"RTU-01","force":false}
预期结果 返回 {"success": false, "message": "独占设备不允许接管"}
通过标准 HTTP 200 但 success=false;NODE-1 设备采集不受影响

TC-08:Shared 设备 - 直接接管

项目 内容
目标 验证 shared 模式设备(如 OPC UA)可不经确认直接接管
前置条件 NODE-1 拥有 OPC UA 设备(access_mode: shared),owner=NODE-1
测试步骤 1. NODE-REMOTE 发起接管
API 调用 POST http://192.168.3.230:8082/api/ownership/takeover {"device_id":"OPCUA-01"}
预期结果 返回 {"success": true, "new_owner": "NODE-REMOTE"};OPCUA-01 的 owner 变更为 NODE-REMOTE
通过标准 takeover 成功;NODE-1 上的 owner 同步更新为 NODE-REMOTE;OWNER_ANNOUNCE 消息广播

TC-09:Lease 设备 - 租约抢占

项目 内容
目标 验证 lease 模式设备(如 Modbus TCP)需等待租约过期或抢占
前置条件 NODE-1 持有 Modbus TCP 设备 PLC-01 的 lease,lease_ttl=30s,renew_interval=15s
测试步骤 1. NODE-REMOTE 发起接管
2. 此时 lease 未过期
API 调用 POST http://192.168.3.230:8082/api/ownership/takeover {"device_id":"PLC-01","force":true}
预期结果 NODE-REMOTE 的请求等待 lease 过期,或 force=true 时立即抢占
takeover_result.lease_acquired=true
通过标准 接管成功后 NODE-1 调度器暂停 PLC-01 采集;NODE-REMOTE 开始采集
调度器验证 检查 NODE-1 日志含 pause collect [PLC-01]、NODE-REMOTE 日志含 start collect [PLC-01]

TC-10:Lease 续约与过期

项目 内容
目标 验证租约续约机制和过期自动释放
前置条件 NODE-1 持有 PLC-01 的 lease
测试步骤 1. 停止 NODE-1(模拟故障)
2. 等待 lease_ttl(30s)过期
3. NODE-REMOTE 尝试获取 lease
API 调用 POST http://192.168.3.230:8082/api/lease/acquire {"device_id":"PLC-01"}
预期结果 30s 后 lease 自动过期,NODE-REMOTE 成功获取 lease
通过标准 NODE-REMOTE 成为新 owner,开始采集

5.5 测试用例:设备更换与配置迁移(P0)

TC-11:设备编码验证

项目 内容
目标 验证设备编码体系正确解析和校验
前置条件 已有设备的编码体系中注册了一台 S7-1200
测试步骤 传入有效和无效的设备编码
API 调用 POST /api/device/code/validate {"device_code":"modbus-siemens-s71200-SN123456789-ABC123"}
预期结果 有效的返回 valid:true 含 device_info;无效的返回 valid:false + 错误信息
通过标准 解析结果正确:protocol=modbus-tcp, vendor=Siemens, model=S7-1200, access_mode=lease

TC-12:设备配置迁移(含接管)

项目 内容
目标 验证通过设备编码实现完整配置迁移
前置条件 NODE-1 拥有完整配置的设备 PLC-01;新设备编码与 PLC-01 匹配
测试步骤 1. 在 NODE-REMOTE 发起迁移请求
2. 系统验证设备编码 → 查找历史配置 → 检查 AccessMode → 处理 Lease
API 调用 POST /api/device/migrate
{"device_code":"modbus-siemens-s71200-SN123456789-ABC123", "target_device_id":"new-plc-01", "migration_scope":["channel","device","northbound"], "preserve_history":true}
预期结果 success:true,migrated_items 含 channel/device/northbound 配置
通过标准 NODE-REMOTE 拥有与 NODE-1 的 PLC-01 完全相同的通道、设备、北向配置

TC-13:迁移回滚

项目 内容
目标 验证配置迁移失败后的回滚机制
前置条件 已完成一次迁移,持有 rollback_key
测试步骤 使用 rollback_key 回滚
API 调用 POST /api/device/migrate/rollback {"rollback_key":"<上一步返回的key>"}
预期结果 配置恢复到迁移前状态
通过标准 所有迁移项被回滚;设备配置与迁移前一致

5.6 测试用例:配置版本管理(P1)

TC-14:Vector Clock 版本比较

项目 内容
目标 验证 Vector Clock 正确识别版本新旧
前置条件 版本向量:NODE-1={NODE-1:12, NODE-2:9},NODE-2={NODE-1:10, NODE-2:9}
测试步骤 触发一致性检查
API 调用 GET /api/sync/consistency
预期结果 报告显示 NODE-1 的版本更新(因为在所有维度上都 >= NODE-2)
通过标准 NODE-1 的配置不会被 NODE-2 覆盖;NODE-2 的版本被标记为 older

TC-15:Vector Clock 冲突检测

项目 内容
目标 验证并发修改产生 Vector Clock 冲突时正确检测
前置条件 NODE-1 和 NODE-2 同时修改同一个 point(产生并发版本)
测试步骤 1. 同时修改 NODE-1 和 NODE-REMOTE 的同一个 point
2. 触发一致性检查
API 调用 GET /api/sync/consistency
预期结果 该 point 被标记为 CONFLICT,overall_status 为 inconsistent
通过标准 冲突被正确识别,UI 显示 ⚠️ CONFLICT 标记

TC-16:配置版本回滚

项目 内容
目标 验证配置可回滚到指定历史版本
前置条件 NODE-1 有至少 3 个版本的配置历史
测试步骤 1. 查询历史版本列表
2. 回滚到 v1
API 调用 GET /api/sync/node/NODE-1/historyPOST /api/sync/node/NODE-1/rollback {"version":1}
预期结果 配置恢复为 v1 版本;version 字段更新为 v1
通过标准 回滚后配置内容与历史 v1 完全一致

5.7 测试用例:数据一致性(P0)

TC-17:一致性检查

项目 内容
目标 验证一致性检查正确识别不一致项
前置条件 NODE-1 和 NODE-REMOTE 存在已知差异
测试步骤 调用全量一致性检查
API 调用 GET /api/sync/consistency
预期结果 返回 overall_status + inconsistent_items 详细列表 + repair_suggestions
通过标准 所有已知差异项出现在 inconsistent_items 中
状态码 consistent(一致)/ inconsistent(不一致)/ degraded(部分降级)

5.8 测试用例:Diff 引擎(P1)

TC-18:结构 Diff(新增/删除)

项目 内容
目标 验证增加新设备和删除点位被正确识别
前置条件 NODE-1 比 NODE-REMOTE 多一个 device,少一个 point
测试步骤 对比两节点差异
API 调用 GET /api/sync/node/NODE-1/diff
预期结果 diff 列表包含 + 新设备 PLC-03(add)、- 删除点位 temp(remove)
通过标准 add/remove 类型 diff 准确

TC-19:属性 Diff(字段变更)

项目 内容
目标 验证字段值变更被正确识别
前置条件 point temp.scale: NODE-1=0.1, NODE-REMOTE=1.0
测试步骤 对比差异
API 调用 GET /api/sync/node/NODE-1/diff
预期结果 type: "update", path: "point.temp.scale", before: 0.1, after: 1.0, level: "info"
通过标准 update 类型 diff 准确

TC-20:语义 Diff(破坏性变更)

项目 内容
目标 验证类型变更被标记为危险级别
前置条件 point val: NODE-1=Integer, NODE-REMOTE=Float
测试步骤 对比差异
API 调用 GET /api/sync/node/NODE-1/diff
预期结果 type: "conflict", level: "critical",UI 显示 ⚠️ 类型变更(破坏性)
通过标准 语义冲突被正确标记为 critical 级别

5.9 测试用例:错误处理与故障恢复(P1)

TC-21:节点离线检测

项目 内容
目标 验证节点离线被正确检测并标记
前置条件 双节点在线
测试步骤 1. 停止 NODE-REMOTE(systemctl stop edgex
2. 等待心跳超时(30s)
API 调用 NODE-1: GET /api/sync/peers
预期结果 NODE-REMOTE 状态变为 offline
通过标准 离线检测时间 ≤ 45s(peer_timeout 30s + 检测周期)

TC-22:节点恢复与断点续传

项目 内容
目标 验证节点恢复后从断点继续同步
前置条件 TC-21 后的状态
测试步骤 1. 重新启动 NODE-REMOTE
2. 在 NODE-1 修改一项配置(离线期间产生差异)
API 调用 观察 sync session 恢复
预期结果 NODE-REMOTE 上线后自动检测差异,发起增量同步,从断点继续
通过标准 NODE-REMOTE 恢复后 60s 内达到一致状态;不会触发全量同步

TC-23:网络超时重试

项目 内容
目标 验证指数退避重试机制
前置条件 双节点在线
测试步骤 1. 临时阻断 NODE-1 → NODE-REMOTE 网络(iptables drop 4001)
2. 触发同步
3. 观察重试行为
预期结果 重试间隔呈指数增长:1s → 2s → 4s(最多 3 次)
通过标准 重试 3 次后标记失败;恢复网络后不丢数据

TC-24:数据冲突自动解决

项目 内容
目标 验证非并发冲突自动以最新版本为准
前置条件 NODE-1 版本 > NODE-REMOTE 版本(非并发)
测试步骤 触发同步
API 调用 POST /api/sync/trigger {"mode":"delta"}
预期结果 NODE-REMOTE 的旧版本被更新为新版本(自动解决)
通过标准 不需要人工介入;同步后一致

5.10 测试用例:所有权管理 API(P0)

TC-25:所有权状态查询

项目 内容
目标 验证所有权状态 API 返回正确信息
API 调用 GET /api/ownership/status
预期结果 返回所有设备的 owner、access_mode、lease 状态
通过标准 exclusive 设备不可接管;shared/lease 设备状态正确

TC-26:所有权转移

项目 内容
目标 验证主动转移设备控制权
前置条件 NODE-1 持有 shared 设备
API 调用 POST /api/ownership/transfer {"device_id":"OPCUA-01","target_node":"NODE-REMOTE"}
预期结果 OPCUA-01 的 owner 变为 NODE-REMOTE;OWNER_ANNOUNCE 广播
通过标准 两个节点 owner 信息一致

5.11 测试用例:UI 界面验证(P1)

TC-27:集群总览页面

项目 内容
目标 验证 UI 集群总览正确展示节点拓扑
步骤 1. 浏览器打开 http://localhost:8082
2. 导航到「集群总览」
预期结果 显示 NODE-1 和 NODE-REMOTE 两个节点,状态指示灯正确
通过标准 节点数量、在线状态、IP 地址、版本号与实际一致

TC-28:配置树导航

项目 内容
目标 验证 GATEWAY → Channel → Device → Point 四级树结构
步骤 1. 点击 NODE-REMOTE 节点
2. 逐级展开 channel → device → points
预期结果 懒加载正常,点 channel 加载 device,点 device 加载 point
通过标准 树结构与 conf/ 目录配置一致;展开/折叠/懒加载正常

TC-29:Diff UI 差异展示

项目 内容
目标 验证差异对比 UI 正确显示
前置条件 两节点存在已知差异
步骤 进入「配置差异」tab
预期结果 显示本地 vs 远程对比,标注 ⚠️ 差异项,提供 [同步到本地] [推送远程] 按钮
通过标准 diff 列表与 API /sync/node/{id}/diff 返回一致

TC-30:侧边栏版本信息展示

项目 内容
目标 验证侧边栏底部正确显示构建版本信息
步骤 1. 浏览器打开 UI
2. 查看左下角 sidebar-footer
预期结果 显示 ● v0.0.4Build 2026-06-05 14:23Commit efa219a
通过标准 版本信息与 GET /api/auth/system-info 返回一致
goreleaser 构建后验证 版本号、构建时间、CommitID 均为真实注入值,而非 dev/unknown

TC-31:接管 UI(AccessMode 分叉)

项目 内容
目标 验证接管按钮按 AccessMode 分叉显示
前置条件 系统中存在 exclusive / shared / lease 三种设备
步骤 1. 逐个查看设备详情
2. 检查接管按钮状态
预期结果 - exclusive: 按钮禁用,显示 🔒
- shared: 按钮正常,显示 🌐,点击直接接管
- lease: 按钮显示 🔁,点击弹确认框”会踢掉对方”
通过标准 三种模式按钮行为与 6.6 节 AccessMode 接管规则一致

5.12 测试用例:配置树结构与懒加载(P1)

TC-32:Channel 层级懒加载

项目 内容
目标 验证展开 Channel 节点时不立即加载所有设备
API 调用 GET /api/sync/node/NODE-1/channel/modbus-1/devices
预期结果 仅返回 channel 下的设备列表,不含 point 详情
通过标准 响应体不含 point,deviceCount 与实际一致

TC-33:Device 层级懒加载

项目 内容
目标 验证展开 Device 节点时才加载该设备的 point 列表
API 调用 GET /api/sync/node/NODE-1/device/PLC-01/points
预期结果 返回 PLC-01 的 point 列表
通过标准 仅返回 PLC-01 的 points;不影响其他 device

5.13 测试用例:并发安全(P1)

TC-34:多节点同时修改不同配置

项目 内容
目标 验证非冲突的并发修改正确合并
前置条件 双节点在线,状态一致
测试步骤 1. NODE-1 修改 device A 的配置
2. 同时 NODE-REMOTE 修改 device B 的配置
3. 两节点互相广播 Announce
预期结果 两项修改都被合并,无冲突
通过标准 最终两节点 device A 和 device B 的配置都正确更新;一致性检查通过

TC-35:同设备多节点并发接管

项目 内容
目标 验证多节点同时接管同一个 lease 设备时不会双主
前置条件 lease 设备 PLC-01 的 lease 已过期
测试步骤 1. NODE-1 和 NODE-REMOTE 同时发起接管
2. 观察冲突解决机制
预期结果 只有一个节点获得 lease(通过 VectorClock 比较或先到先得)
通过标准 同一时刻 PLC-01 只有一个 owner;另一个节点收到 REJECT

6. 异常与边界测试

6.1 异常场景

编号 场景 操作 预期行为
E-01 远程节点断电 直接断开 192.168.3.230 电源 本机检测到 offline,WAL 持久化未同步数据
E-02 网络分区 iptables 阻断两节点间通信 两节点各自正常运行;网络恢复后自动合并
E-03 远程服务崩溃 kill -9 edgex 进程 systemd 自动重启(Restart=always);恢复后增量同步
E-04 磁盘满 远程节点磁盘写满 同步失败,返回错误信息;不损坏已有数据
E-05 配置格式错误 手动写入非法 YAML 解析失败,不传播到其他节点;记录错误日志
E-06 超大配置文件 注入 200 设备 × 500 点的配置 分层 hash 增量同步;不触发全量传输
E-07 版本号溢出 快速连续修改 > 2^32 次 VectorClock 正确处理 uint64 溢出
E-08 重复节点 ID 两节点配置相同 node_id 后启动节点检测冲突,自动重新生成 ID

6.2 边界条件

编号 条件 操作 预期行为
B-01 空配置节点加入 NODE-REMOTE 首次部署,无任何配置 全量同步正常完成
B-02 单节点运行 只有 NODE-1 在线,无其他 peers 正常运行,无异常日志
B-03 设备数为 0 channel 下无 device 树结构正常展示空状态
B-04 点位数为 0 device 下无 point 树结构正常展示空状态
B-05 极长设备名(256+字符) 创建长名称设备 正常创建和同步(或正确拒绝)
B-06 特殊字符设备编码 编码含 / \ : 正确解析或合理拒绝

7. 性能测试

7.1 同步性能基准

指标 条件 预期值 测试方法
全量同步耗时 3 channel / 10 device / 200 point < 5s 计时 sync trigger 到 completed
增量同步耗时 修改 1 个 point < 500ms 计时 point 修改到对端更新
Announce 延迟 局域网内单次广播 < 100ms 测量 hash 变更到对端感知
节点发现时间 新节点加入到被发现 < 10s (mDNS) 计时节点启动到 peers 列表出现
一致性检查耗时 200 point 级检查 < 3s 计时 consistency API 响应
内存占用 空闲运行 < 100MB top / htop
CPU 占用 空闲运行 < 5% top / htop
启动时间 冷启动到 API 可用 < 3s 计时启动命令到 API 响应

7.2 压力测试

指标 条件 验证目标
高频同步 每秒修改 10 个 point,持续 60s 不丢数据、不重复、无崩溃
大配置包 1000 个 point 的 delta 包 正常传输(Snappy 压缩后 < 1MB)
网络延迟 模拟 200ms 延迟 同步正常完成(超时配置需相应调整)

8. 测试执行清单

8.1 执行顺序

Phase 1: 环境准备
  └── [ ] 2.2 环境检查
  └── [ ] 3.1 go run 本地启动
  └── [ ] 3.2 goreleaser 构建
  └── [ ] 4.1 远程部署
  └── [ ] 4.3 部署后验证

Phase 2: 基础功能 (P0)
  └── [ ] TC-01  mDNS 自动发现
  └── [ ] TC-02  Bootstrap 静态发现
  └── [ ] TC-03  新节点加入全量同步
  └── [ ] TC-04  全量配置同步
  └── [ ] TC-05  增量同步
  └── [ ] TC-06  点位级同步
  └── [ ] TC-17  一致性检查

Phase 3: 控制权管理 (P0)
  └── [ ] TC-07  Exclusive 禁止接管
  └── [ ] TC-08  Shared 直接接管
  └── [ ] TC-09  Lease 租约抢占
  └── [ ] TC-10  Lease 续约与过期
  └── [ ] TC-25  所有权状态查询
  └── [ ] TC-26  所有权转移

Phase 4: 设备迁移 (P0)
  └── [ ] TC-11  设备编码验证
  └── [ ] TC-12  设备配置迁移
  └── [ ] TC-13  迁移回滚

Phase 5: 版本与Diff (P1)
  └── [ ] TC-14  Vector Clock 版本比较
  └── [ ] TC-15  Vector Clock 冲突检测
  └── [ ] TC-16  配置版本回滚
  └── [ ] TC-18  结构 Diff
  └── [ ] TC-19  属性 Diff
  └── [ ] TC-20  语义 Diff

Phase 6: 错误处理 (P1)
  └── [ ] TC-21  节点离线检测
  └── [ ] TC-22  节点恢复与断点续传
  └── [ ] TC-23  网络超时重试
  └── [ ] TC-24  数据冲突自动解决

Phase 7: UI验证 (P1)
  └── [ ] TC-27  集群总览页面
  └── [ ] TC-28  配置树导航
  └── [ ] TC-29  Diff UI 差异展示
  └── [ ] TC-30  侧边栏版本信息
  └── [ ] TC-31  接管 UI 分叉

Phase 8: 懒加载 (P1)
  └── [ ] TC-32  Channel 层级懒加载
  └── [ ] TC-33  Device 层级懒加载

Phase 9: 并发安全 (P1)
  └── [ ] TC-34  多节点同时修改不同配置
  └── [ ] TC-35  同设备多节点并发接管

Phase 10: 异常测试
  └── [ ] E-01 ~ E-08  异常场景
  └── [ ] B-01 ~ B-06  边界条件

Phase 11: 性能测试
  └── [ ] 7.1 性能基准
  └── [ ] 7.2 压力测试

8.2 通过标准

级别 标准
P0 全部通过 最小可发布标准
P0 + P1 全部通过 推荐发布标准
异常测试 80% 通过 生产就绪
性能达标 所有指标在预期范围内

9. 快速测试命令集

9.1 本机开发(最常用)

# 构建前端 + 编译运行
cd ui && npm run build && cd ..
go run cmd/main.go

# 验证
curl -s http://localhost:8082/api/auth/system-info | python3 -m json.tool

9.2 远程部署(最常用)

# 一键构建 + 部署
goreleaser release --snapshot --clean --config .goreleaser.yml && \
  bash scripts/deploy-remote.sh root@192.168.3.230 NODE-REMOTE

# 部署后验证
ssh root@192.168.3.230 "systemctl status edgex --no-pager"
ssh root@192.168.3.230 "curl -s http://localhost:8082/api/auth/system-info"

9.3 同步测试

# 获取节点列表
curl -s http://localhost:8082/api/sync/peers | python3 -m json.tool

# 获取远程节点配置树
curl -s http://localhost:8082/api/sync/node/NODE-REMOTE/tree | python3 -m json.tool

# 触发全量同步
curl -s -X POST http://localhost:8082/api/sync/trigger \
  -H 'Content-Type: application/json' \
  -d '{"mode":"full"}' | python3 -m json.tool

# 一致性检查
curl -s http://localhost:8082/api/sync/consistency | python3 -m json.tool

# 所有权状态
curl -s http://localhost:8082/api/ownership/status | python3 -m json.tool

9.4 远程排错

# 查看最近日志
ssh root@192.168.3.230 "journalctl -u edgex -n 100 --no-pager"

# 实时跟踪
ssh root@192.168.3.230 "journalctl -u edgex -f"

# 重启服务
ssh root@192.168.3.230 "systemctl restart edgex"

10. 综合测试检查(10项必须严格验证)

在每次联调测试中,按以下顺序执行,全部通过方可认为系统就绪:

# 检查项 验证命令/方法 通过标准
1 本机启动 go run cmd/main.go → curl sys-info HTTP 200,API 可达
2 goreleaser 构建 goreleaser release --snapshot --clean 所有平台产物生成,无错误
3 远程部署 bash scripts/deploy-remote.sh root@192.168.3.230 NODE-REMOTE systemctl active,API 可达
4 节点发现 curl peers API 双节点互相可见,状态 online
5 全量同步 新节点加入触发或手动 trigger 配置树完全一致
6 增量同步 修改 1 个配置项 → 观察对端更新 仅变更项传递
7 控制权接管 exclusive→拒绝 / shared→直接接管 / lease→抢占 三种模式行为正确
8 一致性检查 curl consistency API overall_status = consistent
9 UI 展示 浏览器确认集群/配置树/Diff/版本信息 数据与 API 一致
10 故障恢复 停止远程节点 → 恢复 offline 检测 + 断点续传正常

文档版本: v3.0(联机测试专用版 + 编译部署 + 35个测试用例)
创建日期: 2026-06-05
适用项目: Industrial Edge Gateway
技术栈: Go 1.25+, go-libp2p, goreleaser
测试节点: 本机 (go run) + 远程 root@192.168.3.230 (deb)
测试覆盖: 节点发现 / 配置同步 / 控制权 / 设备迁移 / 版本管理 / Diff / 错误处理 / UI / 性能