1
0

refactor: 重命名 command checker 为 cmd checker 并适配跨平台测试

将 type/configKey 从 "command" 统一为 "cmd",源码目录 runner/command/ → runner/cmd/,
spec 目录 command-checker/ → cmd-checker/,测试全部改用 bun -e 替代 Unix 系统命令,
归档 cmd-checker-enhancement 变更并同步 delta spec 到主 spec。
This commit is contained in:
2026-05-14 09:23:10 +08:00
parent 0fa2c0c811
commit e983e5d75d
40 changed files with 522 additions and 773 deletions

View File

@@ -58,7 +58,7 @@ src/
registry.ts CheckerRegistry 注册中心
index.ts 注册入口(显式数组 + 循环注册)
http/ HTTP Checker自包含模块含 types/schema/execute/expect/validate/body
command/ Command Checker自包含模块含 types/schema/execute/expect/validate/text
cmd/ Cmd Checker自包含模块含 types/schema/execute/expect/validate/text
shared/
api.ts 前后端共享 TypeScript 类型
web/ React 前端 Dashboard通过 Bun HTML import 集成)
@@ -84,7 +84,7 @@ openspec/ OpenSpec 变更与规格文档
probe-config.schema.json 用户配置 JSON Schema 导出物(用于 IDE 自动补全和校验)
```
> **说明**`runner/http/` 和 `runner/command/` 的完整文件结构见 [1.7.1 架构总览](#171-架构总览) 中的标准文件表。
> **说明**`runner/http/` 和 `runner/cmd/` 的完整文件结构见 [1.7.1 架构总览](#171-架构总览) 中的标准文件表。
## 前后端边界
@@ -227,7 +227,7 @@ export function handleTrend(idStr: string, url: URL, store: ProbeStore, mode: Ru
契约层使用 `src/server/checker/schema/` 中的 TypeBox fragments 生成 JSON Schema并用 Ajv 执行启动期校验。Ajv 必须保持严格拒绝模式:`allErrors: true`、不启用类型强制转换、不注入默认值、不自动删除未知字段。
默认对象策略是 `additionalProperties: false`。只有明确声明的动态键值表可以开放任意键名,例如 `http.headers``defaults.http.headers``expect.headers``command.env`
默认对象策略是 `additionalProperties: false`。只有明确声明的动态键值表可以开放任意键名,例如 `http.headers``defaults.http.headers``expect.headers``cmd.env`
契约校验和语义 validator 都必须返回 `ConfigValidationIssue[]`,不要在 validator 内直接拼接最终用户错误字符串。最终错误由 `formatConfigIssues()` 统一渲染,错误路径需要尽量包含 `targetName``defaults`/root 路径。
@@ -266,11 +266,11 @@ checkerRegistry单例
| `validate.ts` | 启动期语义校验JSON Schema 无法表达的规则) |
| `execute.ts` | Checker 类resolve默认值合并 + 解析、execute执行检查、serializeDB 持久化) |
| `expect.ts` | Checker 专用断言函数 |
| `*.ts` | 其他 checker 专属逻辑(如 http/body.ts、command/text.ts |
| `*.ts` | 其他 checker 专属逻辑(如 http/body.ts、cmd/text.ts |
#### 1.7.2 步骤一:创建 Checker 目录与类型
`src/server/checker/runner/tcp/types.ts` 中定义 checker 专属类型(参考 `http/types.ts``command/types.ts`
`src/server/checker/runner/tcp/types.ts` 中定义 checker 专属类型(参考 `http/types.ts``cmd/types.ts`
- `XxxTargetConfig` — YAML 原始配置类型
- `XxxExpectConfig` — expect 字段类型
@@ -281,7 +281,7 @@ checkerRegistry单例
#### 1.7.3 步骤二:创建 TypeBox 契约 Schema
`src/server/checker/runner/tcp/schema.ts` 中定义 `CheckerSchemas`config / defaults / expect 三部分)。参考 `http/schema.ts``command/schema.ts`,使用 `schema/fragments.ts` 中的共享片段。
`src/server/checker/runner/tcp/schema.ts` 中定义 `CheckerSchemas`config / defaults / expect 三部分)。参考 `http/schema.ts``cmd/schema.ts`,使用 `schema/fragments.ts` 中的共享片段。
**可复用的共享 fragments**(来自 `schema/fragments.ts`
@@ -296,11 +296,11 @@ checkerRegistry单例
| `createPureOperatorSchema()` | 操作符对象 |
| `operatorProperties()` | 所有操作符字段的 Record |
**注意**:默认对象策略为 `additionalProperties: false`。只有明确的动态键值表(如 `http.headers``command.env`)可以开放任意键名。
**注意**:默认对象策略为 `additionalProperties: false`。只有明确的动态键值表(如 `http.headers``cmd.env`)可以开放任意键名。
#### 1.7.4 步骤三:实现语义校验
`src/server/checker/runner/tcp/validate.ts` 中实现 JSON Schema 无法表达的语义规则(参考 `http/validate.ts``command/validate.ts`)。函数签名统一为:
`src/server/checker/runner/tcp/validate.ts` 中实现 JSON Schema 无法表达的语义规则(参考 `http/validate.ts``cmd/validate.ts`)。函数签名统一为:
```typescript
export function validateTcpConfig(input: CheckerValidationInput): ConfigValidationIssue[];
@@ -315,7 +315,7 @@ export function validateTcpConfig(input: CheckerValidationInput): ConfigValidati
#### 1.7.5 步骤四:实现 Checker 类
`src/server/checker/runner/tcp/execute.ts` 中实现 `CheckerDefinition` 接口的全部成员(参考 `http/execute.ts``command/execute.ts`
`src/server/checker/runner/tcp/execute.ts` 中实现 `CheckerDefinition` 接口的全部成员(参考 `http/execute.ts``cmd/execute.ts`
```
TcpChecker implements Checker
@@ -356,7 +356,7 @@ TcpChecker implements Checker
| `operator.ts` | `evaluateJsonPath(json, path)` | JSONPath 提取 |
| `validate-operator.ts` | `validateOperatorObject(ops, path, name)` | 操作符语义校验 |
**Checker 专属断言**(如需要)放在同目录的 `expect.ts` 中,参考 `http/expect.ts`checkStatus、checkHeaders`command/expect.ts`checkExitCode
**Checker 专属断言**(如需要)放在同目录的 `expect.ts` 中,参考 `http/expect.ts`checkStatus、checkHeaders`cmd/expect.ts`checkExitCode
#### 1.7.6 步骤五:创建模块入口并注册
@@ -466,7 +466,7 @@ TcpChecker implements Checker
- **调度**`ProbeEngine``es-toolkit/groupBy` 按 interval 分组,每组独立 `setInterval` 定时触发
- **并发控制**`es-toolkit/Semaphore` 限制全局最大并发数(`maxConcurrentChecks`,默认 20`acquire()` 阻塞等待
- **Runner 选择**`engine.runCheck()` 通过 `checkerRegistry.get(target.type)` 获取 checker并调用 `checker.execute(target, { signal })`
- **超时控制**`ProbeEngine` 为每次检查创建 `AbortController` 并按 `target.timeoutMs` 触发 abortchecker 必须使用 `CheckerContext.signal` 感知超时HTTP 将 signal 传给 `fetch()`Command 在 signal abort 时 `proc.kill()`
- **超时控制**`ProbeEngine` 为每次检查创建 `AbortController` 并按 `target.timeoutMs` 触发 abortchecker 必须使用 `CheckerContext.signal` 感知超时HTTP 将 signal 传给 `fetch()`Cmd 在 signal abort 时 `proc.kill()`
- **结果写入**:检查结果通过 `store.insertCheckResult()` 写入 SQLiteengine 通过 `targetNameToId` 缓存 name→id 映射
- **异常可观测**`probeGroup()``Promise.allSettled` 的 rejected 结果通过索引关联 target并写入 `phase:"internal"` 的失败记录
- **数据清理**:当 `retentionMs > 0`engine 启动时立即执行一次 `store.prune()`,之后每小时定时执行,按 `timestamp` 清理过期数据
@@ -486,7 +486,7 @@ HttpChecker.execute → 收集观测(statusCode/headers)
HTTP checker 的 `durationMs` 覆盖完整执行(含重定向、响应体读取、解码和 expect 校验。status 或 headers 失败时不读取 body进入 body 前若已超过 `maxDurationMs`,直接返回 duration failure。
**Command 校验流程**
**Cmd 校验流程**
```
CommandChecker.execute → 收集观测(exitCode/stdout/stderr/durationMs)
@@ -502,7 +502,7 @@ CommandChecker.execute → 收集观测(exitCode/stdout/stderr/durationMs)
- `css`cheerio CSS 选择器 + 操作符比较
- `xpath`XPath 节点提取 + 操作符比较
**文本规则**`runner/command/text.ts`stdout/stderr 文本匹配,支持 `contains``match`(正则)、操作符比较
**文本规则**`runner/cmd/text.ts`stdout/stderr 文本匹配,支持 `contains``match`(正则)、操作符比较
**操作符**`expect/operator.ts``equals`(深度比较,`es-toolkit/isEqual`)、`contains``match`(正则,启动期通过 `expect/redos.ts` 拒绝 ReDoS 风险模式)、`empty``isNil`+`isEmptyObject`)、`exists``gte`/`lte`/`gt`/`lt`
@@ -522,7 +522,7 @@ CommandChecker.execute → 收集观测(exitCode/stdout/stderr/durationMs)
- `tests/server/checker/runner/shared/duration.test.ts``src/server/checker/expect/duration.ts`
- `tests/server/checker/runner/shared/operator.test.ts``src/server/checker/expect/operator.ts`
- `tests/server/checker/runner/shared/body.test.ts``src/server/checker/runner/http/body.ts`
- `tests/server/checker/runner/shared/text.test.ts``src/server/checker/runner/command/text.ts`
- `tests/server/checker/runner/shared/text.test.ts``src/server/checker/runner/cmd/text.ts`
- 使用 `bun:test` 框架(`describe`/`test`/`expect`),测试数据库用临时目录 + `tmpdir()`
- 新增 store 方法必须编写单元测试;新增 API 端点必须在 `app.test.ts` 中添加集成测试
- 测试后清理:`afterAll``store.close()` + `rm(tempDir, { recursive: true })`
@@ -983,4 +983,4 @@ bun run verify # 完整验证check + 构建)
## 已知限制
当前不做告警通知、拨测目标动态增删、认证鉴权和分布式部署。Command 类型拨测不支持 Windows 环境。
当前不做告警通知、拨测目标动态增删、认证鉴权和分布式部署。