cmvr-es/test/quic_gateway/README.md

301 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CMVR QUIC test Gateway
`cmvr_quic_test_gateway` 是开发和验收工具,不是平台端生产 Gateway。它在本机
监听真实的 MsQuic/TLS/UDP 连接,用来验证 `cmvr_es` 的 QUIC edge v1 客户端。
测试链路:
```text
output/bin/cmvr_es
├── reliable QUIC stream ──> cmvr_quic_test_gateway
│ register / heartbeat / media metadata
└── QUIC DATAGRAM ─────────> bounded media reassembler
```
Gateway 使用生产代码中的:
- `EdgeControlEnvelope` protobuf
- `ControlFrameEncoder` / `ControlFrameDecoder`
- `DatagramPacketizer::decodeHeader`
- `CMQD` v1 常量和类型。
它不会实现 WebTransport、WebRTC、HTTP API、节点数据库或浏览器播放。
## 构建
该目录的 `CMakeLists.txt` 由项目测试目录加入。MsQuic 通过根目录
`request.txt` 提供。依赖为:
- `msquic`
- `cmvr_es::proto`
- `cmvr_es::quic_edge_service`
- `Threads::Threads`
示例:
```bash
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMVR_ARCH=x86 \
-DBUILD_TESTING=ON
cmake --build build --target cmvr_quic_test_gateway -j2
```
默认只生成 build-tree 测试程序,不污染部署目录。如确实希望一同安装:
```bash
cmake -S . -B build \
-DCMVR_INSTALL_QUIC_TEST_GATEWAY=ON
cmake --build build --target cmvr_quic_test_gateway -j2
cmake --install build
```
安装位置是 `output/bin/cmvr_quic_test_gateway`,可复用
`output/lib/libmsquic.so` 和现有相对 RUNPATH。
## 生成本地测试证书
QUIC 即使使用“不校验证书”的 client 模式Server 仍必须提供 TLS 证书。
不要提交真实私钥。下面命令只在 build 目录生成 loopback 测试证书:
```bash
mkdir -p build/test/quic_gateway/certs
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout build/test/quic_gateway/certs/server.key \
-out build/test/quic_gateway/certs/server.crt \
-days 7 \
-subj "/CN=127.0.0.1" \
-addext "subjectAltName=IP:127.0.0.1"
```
MsQuic/OpenSSL 当前要求这里的 PEM 私钥不带密码。
## 启动
固定端口适合人工联调。构建树中请使用 CMake 生成的启动包装器;它会补齐
仓库内 gRPC 等传递动态库的搜索路径:
```bash
build/test/quic_gateway/run_cmvr_quic_test_gateway \
--bind 127.0.0.1 \
--port 4433 \
--cert build/test/quic_gateway/certs/server.crt \
--key build/test/quic_gateway/certs/server.key \
--scenario normal \
--summary-file build/test/quic_gateway/summary.json
```
自动化测试应使用 `--port 0` 避免端口冲突。Gateway 会查询 Listener 实际端口,
在 stdout 和 `--ready-file` 写入一个 JSON 对象:
```bash
build/test/quic_gateway/run_cmvr_quic_test_gateway \
--bind 127.0.0.1 \
--port 0 \
--cert build/test/quic_gateway/certs/server.crt \
--key build/test/quic_gateway/certs/server.key \
--ready-file build/test/quic_gateway/ready.json \
--summary-file build/test/quic_gateway/summary.json \
--exit-after-heartbeats 3
```
Ready 文件示例:
```json
{"event":"ready","bind":"127.0.0.1:52319","port":52319,"alpn":"cmvr-quic-edge/1","scenario":"normal","datagram_enabled":true}
```
自动 runner 读取 `port`,将它写入临时 `quic_edge_task.pb.txt` 后再启动
`cmvr_es`。不要直接改唯一一份 `output/bin/config/`;普通安装默认会覆盖它。
只更新程序与运行库时,应在配置构建目录时设置
`-DCMVR_INSTALL_DEFAULT_RUNTIME_ASSETS=OFF`
## cmvr_es 本机配置
第一轮只测试注册、IP 上报和心跳,保持设备和 `tracks` 关闭:
```protobuf
quic_edge {
id: "quic_edge"
server_host: "127.0.0.1"
server_port: 4433
alpn: "cmvr-quic-edge/1"
node_id: "local-quic-test"
software_version: "test"
grpc_endpoint_host: "127.0.0.1"
grpc_endpoint_port: 50052
grpc_endpoint_tls: false
include_loopback_interfaces: true
heartbeat_interval_ms: 1000
control_response_timeout_ms: 1000
tls {
allow_insecure: true
}
reconnect {
initial_delay_ms: 100
maximum_delay_ms: 1000
multiplier: 2.0
jitter_percent: 0
connect_timeout_ms: 3000
}
maximum_datagram_bytes: 1200
maximum_control_frame_bytes: 1048576
maximum_frame_bytes: 524288
datagram_send_queue_depth: 512
media_poll_interval_ms: 2
}
```
在 TaskManager 中将 `quic_edge` entry 设为 `enable: true`。然后运行一份独立的
临时配置树:
```bash
output/bin/cmvr_es /tmp/cmvr-quic-e2e/config/cmvr_es.pb.txt
```
## 场景
`--scenario` 支持:
当前 CTest 自动回归仅运行 `normal` 场景;其余场景保留为手工故障注入和验收入口,
尚未纳入自动回归。
| 名称 | 行为 | 预期 Edge 行为 |
| --- | --- | --- |
| `normal` | 接受注册并精确 ACK 心跳 | 保持同一连接 |
| `reject-registration` | 返回 `accepted=false` | 退避后重新注册 |
| `drop-heartbeat-ack` | 接收但不回复心跳 | response timeout 后重连 |
| `wrong-ack-session` | ACK 使用错误 session ID | 判定协议错误并重连 |
| `fatal-protocol-error` | 注册成功后发送 fatal `ProtocolError` | 重连 |
| `nonfatal-protocol-error` | 注册成功后发送 nonfatal `ProtocolError` | 保持连接并继续心跳 |
| `datagram-disabled` | 不协商 QUIC DATAGRAM | 注册和心跳正常,媒体不发送 |
可以用以下条件让程序自动成功退出:
- `--exit-after-registrations N`
- `--exit-after-heartbeats N`
- `--run-for-ms N`
收到 `SIGINT``SIGTERM`Gateway 会停止 Listener、关闭活动连接、排空工作
队列并写 summary。
## 协议验证
每个连接独立维护:
- control framing buffer
- Edge 和 Gateway 各自的严格递增 `message_sequence`
- node、boot、registration session
- media session epoch
- track descriptor generation token
- DATAGRAM 重组缓存。
Gateway 要求:
1. `NodeRegisterRequest` 是第一条应用消息;
2. protocol version 为 1
3. 后续 envelope sequence 严格增加;
4. heartbeat 的 node、boot 和 session 与注册一致;
5. media session 先于 descriptor
6. DATAGRAM 的 epoch、track、kind 和 generation token 与可靠元数据一致。
`observed_source_ip` 从 MsQuic peer address 获取,不从 Edge 上报字段复制。
Heartbeat 中存在 `device_manager`Gateway 会记录 Manager 元数据以及设备
总数、启用数、禁用数、确认异常数和未知健康数;该字段是 v1 的兼容性追加项,
并在最终 summary 的 `heartbeat_devices` 数组中保留最近一次完整设备行。测试
Gateway 仍接受没有该字段的旧 Edge。当前 Edge 只发送已启用设备,因此正常情况
下禁用数为 0该统计仍用于兼容旧发送端和发现协议违规。
summary 还会保留每类媒体最近一次 descriptor以及已完成帧中的最大
`frame_sequence`、长度、flags、采集时间戳和 FNV-1a 64 位载荷哈希。这里的哈希
只用于测试中精确比对字节,不用于安全认证。真实 E2E 会先发送 discovery 帧并等
descriptor 到达,再发送 priming/validation 帧,从而避免 reliable stream 与
DATAGRAM 跨通道乱序造成偶发误判。
## DATAGRAM 安全边界
MsQuic callback 只复制收到的数据并进入有界队列;控制消息使用高优先级队列,
不会被媒体洪峰长期阻塞。后台线程完成 protobuf 处理和媒体重组。
重组 key 是:
```text
(session_epoch, track_id, frame_sequence)
```
接收器限制:
- 总缓存字节;
- 在途帧数;
- 单帧大小;
- 单帧最多 8192 个分片;
- 不完整帧超时;
- fragment index 冲突;
- byte range 重叠;
- 新 session epoch 清理旧分片。
相关 CLI
```text
--max-reassembly-bytes
--max-reassembly-frames
--max-frame-bytes
--max-work-queue-bytes
--reassembly-timeout-ms
```
## 输出与判定
stdout 每行都是一个 JSON 对象或 JSON-compatible 单行事件。最终 summary 包含:
- connection/register/heartbeat 计数;
- 注册和最近一次心跳上报的网卡数量、gRPC endpoint 与对端源 IP
- 最近一次 DeviceManager 名称/版本/描述,以及已上报设备总数、启用数、兼容性
禁用数、确认异常数、未知健康数和 `heartbeat_devices` 完整设备行;
- ACK、故障场景和协议错误计数
- media session/descriptor/DATAGRAM 计数;
- 完整帧(含视频/音频分项)、无效包、队列丢包;
- 超时、容量淘汰和 session 清理的不完整帧。
自动化脚本至少应检查:
```text
runtime_failed == false
registrations_accepted >= 1 # normal 场景
heartbeats_received >= 1
heartbeat_acks_sent >= 1
protocol_violations == 0
```
媒体场景还应检查:
```text
media_sessions_opened >= 1
track_descriptors_received >= 1
datagrams_received >= 1
frames_completed >= 1
```
## 无设备主机的限制
关闭全部设备时,实际 `output/bin/cmvr_es` 可以完整验证 TLS、ALPN、控制 stream、
注册、IP 上报、心跳和重连,但不会产生音视频。
要在无硬件环境验证媒体 DATAGRAM测试侧还需要 synthetic MediaSourceHub producer
或测试专用 fake camera/microphone。该 Gateway 已具备媒体接收和重组能力,但不会
伪造 Edge 发出的媒体。
## 安全说明
- 仅监听 loopback 是默认值;
- `allow_insecure` 仅限本机开发;
- 不要将测试 Gateway 暴露到不受信任网络;
- 不要复用或提交生产证书、生产私钥;
- 该工具没有生产级认证、授权、持久化和多租户隔离。