1
0

refactor: ICMP checker type 从 ping 统一改为 icmp,修复前端 UI 细节

- ICMP checker 的 type/configKey/YAML 配置键/接口属性名从 ping 改为 icmp
- IcmpChecker 添加 platform 构造函数注入,修复 Windows 测试兼容性
- 前端 target 表格延迟列优化:标题简化为「延迟」,单位下移到单元格,宽度 80px
- Drawer 概览页 Descriptions 添加 tableLayout=auto 收窄 label 宽度
- 同步更新 README.md、DEVELOPMENT.md、probes.example.yaml、JSON Schema 和全部测试
This commit is contained in:
2026-05-20 00:02:23 +08:00
parent 375dd3492b
commit 9b53c746f6
23 changed files with 239 additions and 224 deletions

View File

@@ -1,84 +1,88 @@
## Purpose
定义 ICMP/Ping checker 的配置格式、命令执行、跨平台输出解析、expect 校验、失败结构和状态摘要。
定义 ICMP checker 的配置格式、命令执行、跨平台输出解析、expect 校验、失败结构和状态摘要。
## Requirements
### Requirement: ping target 配置
系统 SHALL 支持 `type: ping` 的 target 配置,通过 `ping.host` 描述目标主机地址,并通过可选字段控制探测行为。
### Requirement: icmp target 配置
系统 SHALL 支持 `type: icmp` 的 target 配置,通过 `icmp.host` 描述目标主机地址,并通过可选字段控制探测行为。
#### Scenario: 解析最简 ping target
- **WHEN** YAML 中 target 配置 `type: ping``ping.host: "10.0.0.1"`
- **THEN** 系统 SHALL 将其解析为 ping checker并填充 `count=3``packetSize=56`、interval、timeout、group 和 expect 配置
#### Scenario: 解析最简 icmp target
- **WHEN** YAML 中 target 配置 `type: icmp``icmp.host: "10.0.0.1"`
- **THEN** 系统 SHALL 将其解析为 icmp checker并填充 `count=3``packetSize=56`、interval、timeout、group 和 expect 配置
#### Scenario: ping target 缺少 host
- **WHEN** YAML 中 target 配置 `type: ping` 但缺少 `ping.host`
- **THEN** 系统 SHALL 以配置错误退出,并提示该 target 缺少 ping.host 字段
#### Scenario: icmp target 缺少 host
- **WHEN** YAML 中 target 配置 `type: icmp` 但缺少 `icmp.host`
- **THEN** 系统 SHALL 以配置错误退出,并提示该 target 缺少 icmp.host 字段
#### Scenario: ping host 类型非法
- **WHEN** YAML 中 ping target 的 `ping.host` 不是非空字符串
- **THEN** 系统 SHALL 以配置错误退出,提示 ping.host 必须为非空字符串
#### Scenario: icmp host 类型非法
- **WHEN** YAML 中 icmp target 的 `icmp.host` 不是非空字符串
- **THEN** 系统 SHALL 以配置错误退出,提示 icmp.host 必须为非空字符串
#### Scenario: ping count 配置
- **WHEN** YAML 中 ping target 配置 `ping.count: 5`
#### Scenario: icmp count 配置
- **WHEN** YAML 中 icmp target 配置 `icmp.count: 5`
- **THEN** 系统 SHALL 使用 5 作为 ICMP 包发送数量
#### Scenario: ping count 非法
- **WHEN** YAML 中 ping target 的 `ping.count` 不是 1 到 100 之间的正整数
- **THEN** 系统 SHALL 以配置错误退出,提示 ping.count 必须为 1-100 的正整数
#### Scenario: icmp count 非法
- **WHEN** YAML 中 icmp target 的 `icmp.count` 不是 1 到 100 之间的正整数
- **THEN** 系统 SHALL 以配置错误退出,提示 icmp.count 必须为 1-100 的正整数
#### Scenario: ping packetSize 配置
- **WHEN** YAML 中 ping target 配置 `ping.packetSize: 1472`
#### Scenario: icmp packetSize 配置
- **WHEN** YAML 中 icmp target 配置 `icmp.packetSize: 1472`
- **THEN** 系统 SHALL 使用 1472 作为 ICMP 包大小bytes
#### Scenario: ping packetSize 非法
- **WHEN** YAML 中 ping target 的 `ping.packetSize` 不是 1 到 65500 之间的正整数
- **THEN** 系统 SHALL 以配置错误退出,提示 ping.packetSize 必须为 1-65500 的正整数
#### Scenario: icmp packetSize 非法
- **WHEN** YAML 中 icmp target 的 `icmp.packetSize` 不是 1 到 65500 之间的正整数
- **THEN** 系统 SHALL 以配置错误退出,提示 icmp.packetSize 必须为 1-65500 的正整数
#### Scenario: ping 分组未知字段失败
- **WHEN** YAML 中 ping target 的 `ping` 分组包含 `timeout: 5` 等未知字段
- **THEN** 系统 SHALL 以配置错误退出,提示 ping 分组包含未知字段
#### Scenario: icmp 分组未知字段失败
- **WHEN** YAML 中 icmp target 的 `icmp` 分组包含 `timeout: 5` 等未知字段
- **THEN** 系统 SHALL 以配置错误退出,提示 icmp 分组包含未知字段
#### Scenario: ping 序列化展示摘要
- **WHEN** 系统同步 ping target 到 targets 表
- **THEN** `target` 展示摘要 SHALL 为 `ping <host>``config` JSON SHALL 包含 resolved 后的 host、count 和 packetSize
#### Scenario: icmp 序列化展示摘要
- **WHEN** 系统同步 icmp target 到 targets 表
- **THEN** `target` 展示摘要 SHALL 为 `icmp <host>``config` JSON SHALL 包含 resolved 后的 host、count 和 packetSize
### Requirement: ping checker 执行
系统 SHALL 通过调用系统 `ping` 命令执行 ICMP 探测,记录完整执行耗时,并在命令不可用、超时或解析失败时产生结构化失败信息。
### Requirement: icmp checker 执行
系统 SHALL 通过调用系统 `ping` 命令执行 ICMP 探测,记录完整执行耗时,并在命令不可用、超时或解析失败时产生结构化失败信息。`IcmpChecker` SHALL 通过构造函数参数支持 platform 注入,默认使用 `process.platform`
#### Scenario: ping 命令构建Linux
- **WHEN** 系统平台为 linuxping target 配置 host="10.0.0.1"、count=3、packetSize=56且外层 timeoutMs=10000
- **WHEN** 系统平台为 linuxicmp target 配置 host="10.0.0.1"、count=3、packetSize=56且外层 timeoutMs=10000
- **THEN** 系统 SHALL 执行 `ping -c 3 -s 56 -W 10 10.0.0.1`-W 单位为秒,向上取整)
#### Scenario: ping 命令构建macOS
- **WHEN** 系统平台为 darwinping target 配置 host="10.0.0.1"、count=3、packetSize=56且外层 timeoutMs=10000
- **WHEN** 系统平台为 darwinicmp target 配置 host="10.0.0.1"、count=3、packetSize=56且外层 timeoutMs=10000
- **THEN** 系统 SHALL 执行 `ping -c 3 -s 56 -W 10000 10.0.0.1`-W 单位为毫秒)
#### Scenario: ping 命令构建Windows
- **WHEN** 系统平台为 win32ping target 配置 host="10.0.0.1"、count=3、packetSize=56且外层 timeoutMs=10000
- **WHEN** 系统平台为 win32icmp target 配置 host="10.0.0.1"、count=3、packetSize=56且外层 timeoutMs=10000
- **THEN** 系统 SHALL 执行 `ping -n 3 -l 56 -w 10000 10.0.0.1`-w 单位为毫秒)
#### Scenario: ping 命令不存在
- **WHEN** 系统未安装 `ping` 命令spawn 抛出 ENOENT
- **THEN** 系统 SHALL 记录 `matched=false`failure 的 kind 为 `error`phase 为 `ping`path 为 `spawn`message 包含 "ping 命令不可用" 和原始错误信息
- **THEN** 系统 SHALL 记录 `matched=false`failure 的 kind 为 `error`phase 为 `icmp`path 为 `spawn`message 包含 "icmp 命令不可用" 和原始错误信息
#### Scenario: ping 执行超时
- **WHEN** 引擎注入的 `ctx.signal` 在 ping 命令执行过程中 abort
- **THEN** 系统 SHALL 调用 `proc.kill()` 终止子进程,记录 `matched=false`failure 的 kind 为 `error`phase 为 `ping`message 包含超时信息
- **THEN** 系统 SHALL 调用 `proc.kill()` 终止子进程,记录 `matched=false`failure 的 kind 为 `error`phase 为 `icmp`message 包含超时信息
#### Scenario: ping 目标可达
- **WHEN** ping target 指向可达主机,且 ping 命令正常返回
- **WHEN** icmp target 指向可达主机,且 ping 命令正常返回
- **THEN** 系统 SHALL 解析 stdout 获取统计数据,并按断言链执行 expect 校验
#### Scenario: ping 目标不可达
- **WHEN** ping target 指向不可达主机,且 ping 命令返回 100% packet loss
- **WHEN** icmp target 指向不可达主机,且 ping 命令返回 100% packet loss
- **THEN** 系统 SHALL 解析 stdout 获取统计数据,`alive` 为 false延迟字段为 null
#### Scenario: duration 覆盖完整执行
- **WHEN** ping 命令执行完成
- **THEN** 结果中的 `durationMs` SHALL 覆盖从 spawn 到进程退出的完整耗时
### Requirement: 跨平台 ping 输出解析
#### Scenario: platform 注入用于测试
- **WHEN** 构造 `new IcmpChecker("linux")`
- **THEN** execute 方法 SHALL 使用注入的 "linux" 作为平台参数,而非 `process.platform`
### Requirement: 跨平台 icmp 输出解析
系统 SHALL 实现跨平台 ping 输出解析器,支持 Linux、macOS 和 Windows含多语言 locale从 stdout 中提取 transmitted、received、packetLoss、minLatencyMs、avgLatencyMs、maxLatencyMs。
#### Scenario: 解析 Linux ping 输出
@@ -103,86 +107,86 @@
#### Scenario: 输出无法解析
- **WHEN** stdout 不匹配任何已知的统计行格式
- **THEN** 系统 SHALL 记录 `matched=false`failure 的 kind 为 `error`phase 为 `ping`path 为 `parse`message 包含 "无法解析 ping 输出"
- **THEN** 系统 SHALL 记录 `matched=false`failure 的 kind 为 `error`phase 为 `icmp`path 为 `parse`message 包含 "无法解析 icmp 输出"
### Requirement: ping expect 校验
系统 SHALL 支持 ping 专属 expect包括 `alive``packetLossPercent``avgLatencyMs``maxLatencyMs``durationMs`,并按 alive、packetLossPercent、avgLatencyMs、maxLatencyMs、durationMs 的阶段顺序快速失败。`alive` SHALL 保持布尔状态语义,未配置时默认 `true``packetLossPercent` SHALL 表示 0 到 100 的丢包率百分比,并使用共享 `ValueMatcher``avgLatencyMs``maxLatencyMs``durationMs` SHALL 使用共享 `ValueMatcher`
### Requirement: icmp expect 校验
系统 SHALL 支持 icmp 专属 expect包括 `alive``packetLossPercent``avgLatencyMs``maxLatencyMs``durationMs`,并按 alive、packetLossPercent、avgLatencyMs、maxLatencyMs、durationMs 的阶段顺序快速失败。`alive` SHALL 保持布尔状态语义,未配置时默认 `true``packetLossPercent` SHALL 表示 0 到 100 的丢包率百分比,并使用共享 `ValueMatcher``avgLatencyMs``maxLatencyMs``durationMs` SHALL 使用共享 `ValueMatcher`
#### Scenario: 默认 alive 成功语义
- **WHEN** ping target 未显式配置 `expect.alive`
- **WHEN** icmp target 未显式配置 `expect.alive`
- **THEN** 系统 SHALL 使用默认 `expect.alive: true` 进行校验
#### Scenario: alive 校验通过
- **WHEN** ping target 配置 `expect.alive: true`,且目标主机可达
- **WHEN** icmp target 配置 `expect.alive: true`,且目标主机可达
- **THEN** 系统 SHALL 判定 alive 阶段通过
#### Scenario: alive 校验失败
- **WHEN** ping target 配置 `expect.alive: true`,且目标主机不可达
- **WHEN** icmp target 配置 `expect.alive: true`,且目标主机不可达
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 kind 为 `mismatch`phase 为 `alive`
#### Scenario: 反向 alive 断言
- **WHEN** ping target 配置 `expect.alive: false`,且目标主机不可达
- **WHEN** icmp target 配置 `expect.alive: false`,且目标主机不可达
- **THEN** 系统 SHALL 判定 alive 阶段通过(`matched=true`
#### Scenario: packetLossPercent 校验通过
- **WHEN** ping target 配置 `expect.packetLossPercent: {lte: 10}`,且实际丢包率为 0%
- **WHEN** icmp target 配置 `expect.packetLossPercent: {lte: 10}`,且实际丢包率为 0%
- **THEN** 系统 SHALL 判定 packetLossPercent 阶段通过
#### Scenario: packetLossPercent 校验失败
- **WHEN** ping target 配置 `expect.packetLossPercent: {lte: 10}`,且实际丢包率为 33%
- **WHEN** icmp target 配置 `expect.packetLossPercent: {lte: 10}`,且实际丢包率为 33%
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 kind 为 `mismatch`phase 为 `packetLoss`
#### Scenario: avgLatencyMs 校验通过
- **WHEN** ping target 配置 `expect.avgLatencyMs: {lte: 200}`,且实际平均延迟为 12ms
- **WHEN** icmp target 配置 `expect.avgLatencyMs: {lte: 200}`,且实际平均延迟为 12ms
- **THEN** 系统 SHALL 判定 avgLatency 阶段通过
#### Scenario: avgLatencyMs 校验失败
- **WHEN** ping target 配置 `expect.avgLatencyMs: {lte: 100}`,且实际平均延迟为 156ms
- **WHEN** icmp target 配置 `expect.avgLatencyMs: {lte: 100}`,且实际平均延迟为 156ms
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 kind 为 `mismatch`phase 为 `avgLatency`
#### Scenario: maxLatencyMs 校验通过
- **WHEN** ping target 配置 `expect.maxLatencyMs: {lte: 500}`,且实际最大延迟为 340ms
- **WHEN** icmp target 配置 `expect.maxLatencyMs: {lte: 500}`,且实际最大延迟为 340ms
- **THEN** 系统 SHALL 判定 maxLatency 阶段通过
#### Scenario: maxLatencyMs 校验失败
- **WHEN** ping target 配置 `expect.maxLatencyMs: {lte: 200}`,且实际最大延迟为 340ms
- **WHEN** icmp target 配置 `expect.maxLatencyMs: {lte: 200}`,且实际最大延迟为 340ms
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 kind 为 `mismatch`phase 为 `maxLatency`
#### Scenario: durationMs 校验
- **WHEN** ping target 配置 `expect.durationMs: {lte: 5000}`,且完整执行耗时超过 5000ms
- **WHEN** icmp target 配置 `expect.durationMs: {lte: 5000}`,且完整执行耗时超过 5000ms
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 phase 为 `duration`
#### Scenario: alive=false 时跳过延迟断言
- **WHEN** ping target 配置 `expect.alive: true``expect.avgLatencyMs: {lte: 100}`,且目标不可达
- **WHEN** icmp target 配置 `expect.alive: true``expect.avgLatencyMs: {lte: 100}`,且目标不可达
- **THEN** 系统 SHALL 在 alive 阶段即返回失败,不执行后续延迟断言
#### Scenario: ping expect 未知字段失败
- **WHEN** YAML 中 ping target 的 expect 包含 `status: [200]``maxPacketLoss``maxAvgLatencyMs``maxMaxLatencyMs``maxDurationMs` 或其他非 ping expect 字段
#### Scenario: icmp expect 未知字段失败
- **WHEN** YAML 中 icmp target 的 expect 包含 `status: [200]``maxPacketLoss``maxAvgLatencyMs``maxMaxLatencyMs``maxDurationMs` 或其他非 icmp expect 字段
- **THEN** 系统 SHALL 以配置错误退出,提示 expect 包含未知字段
#### Scenario: packetLossPercent 类型非法
- **WHEN** YAML 中 ping target 的 `expect.packetLossPercent` 不是合法 `ValueMatcher`,或其数值范围无法用于 0 到 100 的百分比断言
- **WHEN** YAML 中 icmp target 的 `expect.packetLossPercent` 不是合法 `ValueMatcher`,或其数值范围无法用于 0 到 100 的百分比断言
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.packetLossPercent 格式错误
#### Scenario: avgLatencyMs 类型非法
- **WHEN** YAML 中 ping target 的 `expect.avgLatencyMs` 不是合法 `ValueMatcher`
- **WHEN** YAML 中 icmp target 的 `expect.avgLatencyMs` 不是合法 `ValueMatcher`
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.avgLatencyMs 格式错误
#### Scenario: maxLatencyMs 类型非法
- **WHEN** YAML 中 ping target 的 `expect.maxLatencyMs` 不是合法 `ValueMatcher`
- **WHEN** YAML 中 icmp target 的 `expect.maxLatencyMs` 不是合法 `ValueMatcher`
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.maxLatencyMs 格式错误
### Requirement: ping detail 摘要
系统 SHALL 在 ping API 序列化时从 observation 动态生成结构化 detail 摘要展示关键指标。API registry type SHALL 仍为 `ping`
### Requirement: icmp detail 摘要
系统 SHALL 在 icmp API 序列化时从 observation 动态生成结构化 detail 摘要展示关键指标。API registry type SHALL 仍为 `icmp`
#### Scenario: 目标可达无丢包
- **WHEN** ping observation 为 alive=true, avgLatencyMs=12, packetLoss=0%, transmitted=3, received=3
- **WHEN** icmp observation 为 alive=true, avgLatencyMs=12, packetLoss=0%, transmitted=3, received=3
- **THEN** detail SHALL 为 `alive, avg 12ms, loss 0% (3/3)`
#### Scenario: 目标可达有丢包
- **WHEN** ping observation 为 alive=true, avgLatencyMs=156, maxLatencyMs=340, packetLoss=33%, transmitted=3, received=2
- **WHEN** icmp observation 为 alive=true, avgLatencyMs=156, maxLatencyMs=340, packetLoss=33%, transmitted=3, received=2
- **THEN** detail SHALL 包含 avg、max 和 loss 信息
#### Scenario: 目标不可达
- **WHEN** ping observation 为 alive=false, transmitted=3, received=0
- **WHEN** icmp observation 为 alive=false, transmitted=3, received=0
- **THEN** detail SHALL 为 `unreachable (0/3 received)`