1
0
Files
DiAL/openspec/specs/db-checker/spec.md
lanyuanxiaoyao 7a635a0a9f refactor: 统一 expect 断言体系,引入共享 ValueMatcher/ContentRules/KeyValueExpect 模型
- 引入共享 ValueMatcher(equals/contains/regex/exists/empty/gt/gte/lt/lte)
- 引入共享 ContentRules 数组(direct/json/css/xpath 提取器)
- 引入共享 KeyValueExpect(动态键值断言,字面量等价 equals)
- maxDurationMs → durationMs: ValueMatcher(所有 checker)
- match → regex(固定无 flags)
- Ping max* → packetLossPercent/avgLatencyMs/maxLatencyMs(ValueMatcher)
- LLM finishReason/rawFinishReason → ValueMatcher
- DB 新增 result: ContentRules
- TCP banner → ContentRules 数组
- 删除旧模块:operator.ts、validate-operator.ts、duration.ts、body.ts、text.ts、output.ts
- 更新全部 checker schema/validate/expect/execute
- 更新 probe-config.schema.json、probes.example.yaml
- 更新 README.md、DEVELOPMENT.md(含 expect 字段选择规范)
- 同步 10 个 delta specs 到主 specs,归档 change
2026-05-19 14:24:27 +08:00

154 lines
9.1 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.
## Purpose
定义 db 类型拨测目标的配置格式、执行逻辑、expect 断言规则和启动期校验。
## Requirements
### Requirement: db target 配置
系统 SHALL 支持 `type: db` 的 target 配置,通过 `db.url` 描述数据库连接字符串(遵循 Bun SQL 支持的格式),通过可选的 `db.query` 描述待执行的 SQL 语句。
#### Scenario: 解析仅连接的 db target
- **WHEN** YAML 中 target 配置 `type: db``db.url: "postgres://user:pass@localhost:5432/mydb"`,未配置 `db.query`
- **THEN** 系统 SHALL 将其解析为 db checker仅执行连通性检测
#### Scenario: 解析带查询的 db target
- **WHEN** YAML 中 target 配置 `type: db``db.url: "mysql://user:pass@host:3306/app"``db.query: "SELECT count(*) as cnt FROM users"`
- **THEN** 系统 SHALL 将其解析为 db checker执行连通性检测后执行指定 SQL 并进入 expect 校验
#### Scenario: db target 缺少 url
- **WHEN** YAML 中 target 配置 `type: db` 但缺少 `db.url`
- **THEN** 系统 SHALL 以配置错误退出,并提示该 target 缺少 db.url 字段
#### Scenario: db.url 为空字符串
- **WHEN** YAML 中 target 配置 `db.url: ""`
- **THEN** 系统 SHALL 以配置错误退出,并提示 db.url 不能为空
#### Scenario: db.query 为空字符串
- **WHEN** YAML 中 target 配置 `db.query: ""`
- **THEN** 系统 SHALL 以配置错误退出,并提示 db.query 不能为空字符串(如不需要查询则不配置该字段)
#### Scenario: db 分组未知字段失败
- **WHEN** YAML 中 db target 的 `db` 分组包含 `timeout: 5` 等未知字段
- **THEN** 系统 SHALL 以配置错误退出,提示 db 分组包含未知字段
#### Scenario: SQLite 连接字符串
- **WHEN** YAML 中 target 配置 `db.url: "sqlite:///data/app.db"`
- **THEN** 系统 SHALL 将其解析为 db checker使用 SQLite 文件数据库
#### Scenario: url 格式由 Bun 运行时校验
- **WHEN** YAML 中 target 配置 `db.url` 为 Bun 不支持的格式
- **THEN** 系统 SHALL 在执行阶段捕获连接错误并作为 phase="connect" 的 failure 返回,而非在启动期校验 URL 格式
### Requirement: db checker 执行
系统 SHALL 按 db target 配置连接数据库并执行查询,每次执行都新建连接并在完成后关闭。连接能力本身作为监控指标。
#### Scenario: 仅连接测试成功
- **WHEN** db target 未配置 `db.query` 且数据库连接成功
- **THEN** 系统 SHALL 内部执行 `SELECT 1` 验证连通性,记录 `matched=true``durationMs`
#### Scenario: 连接失败
- **WHEN** db target 的数据库连接失败(网络不通、认证错误、数据库不存在等)
- **THEN** 系统 SHALL 记录 `matched=false`failure 的 phase 为 `"connect"`message 包含可读错误信息
#### Scenario: 查询执行成功
- **WHEN** db target 配置了 `db.query` 且 SQL 执行成功返回结果集
- **THEN** 系统 SHALL 记录 `durationMs`(从连接开始到查询完成),并进入 expect 校验
#### Scenario: 查询执行失败
- **WHEN** db target 配置了 `db.query` 且 SQL 执行报错(语法错误、权限不足、表不存在等)
- **THEN** 系统 SHALL 记录 `matched=false`failure 的 phase 为 `"query"`message 包含数据库返回的错误信息
#### Scenario: 执行超时
- **WHEN** db target 在 timeout 时间内未完成(连接或查询)
- **THEN** 系统 SHALL 关闭连接,记录 `matched=false`failure 的 phase 为 `"connect"``"query"`取决于超时发生的阶段message 包含超时信息
#### Scenario: 每次执行新建连接
- **WHEN** db target 被引擎调度执行
- **THEN** 系统 SHALL 创建新的 SQL 连接实例max: 1执行完成后立即关闭连接close timeout: 0
#### Scenario: 使用 unsafe 执行用户 SQL
- **WHEN** db target 配置了 `db.query`
- **THEN** 系统 SHALL 使用 `sql.unsafe(query)` 执行用户配置的 SQL 文本,不限制 SQL 类型
#### Scenario: 响应 abort signal
- **WHEN** 引擎注入的 `ctx.signal` 被 abort
- **THEN** 系统 SHALL 立即关闭数据库连接
### Requirement: db expect 校验
系统 SHALL 支持 db 专用 expect包括 `durationMs``rowCount``rows``result`,按 durationMs、rowCount、rows、result 的阶段顺序快速失败。`durationMs``rowCount` SHALL 使用共享 `ValueMatcher``rows` SHALL 保留按行索引匹配列值的语义,类型为 `Array<KeyValueExpect>`(外层数组按行索引,内层每个元素为一个 `KeyValueExpect` 表达该行的列值断言),每个行规则中列值字面量等价于 `{equals: <literal>}``result` MUST 使用共享 `ContentRules` 数组,对查询结果对象 `{ rows, rowCount }` 执行断言。
#### Scenario: durationMs 校验
- **WHEN** db target 配置 `expect.durationMs: {lte: 3000}` 且实际执行耗时 4000ms
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 phase 为 `duration`
#### Scenario: rowCount 校验通过
- **WHEN** db target 配置 `expect.rowCount: { gte: 1 }` 且查询返回 5 行
- **THEN** 系统 SHALL 判定 rowCount 阶段通过,继续后续 expect 阶段
#### Scenario: rowCount 校验失败
- **WHEN** db target 配置 `expect.rowCount: { gte: 1 }` 且查询返回 0 行
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 phase 为 `rowCount`path 为 `rowCount`expected 为 `{ gte: 1 }`actual 为 0
#### Scenario: rows 按索引匹配列值 matcher 形式
- **WHEN** db target 配置 `expect.rows: [{ cnt: { gte: 100 } }]` 且查询首行 cnt 列值为 50
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 phase 为 `row`path 为 `rows[0].cnt`
#### Scenario: rows 按索引匹配列值字面量形式
- **WHEN** db target 配置 `expect.rows: [{ status: "active" }]` 且查询首行 status 列值为 `"active"`
- **THEN** 系统 SHALL 判定该行该列通过(字面量等价于 `{ equals: "active" }`
#### Scenario: rows 只检查声明的列
- **WHEN** db target 配置 `expect.rows: [{ cnt: { gte: 1 } }]` 且查询首行包含 cnt、name、age 三列
- **THEN** 系统 SHALL 仅检查 cnt 列,忽略 name 和 age 列
#### Scenario: rows 结果行数不足
- **WHEN** db target 配置 `expect.rows` 包含 3 个元素但查询仅返回 2 行
- **THEN** 系统 SHALL 返回 `matched=false`failure 的 phase 为 `row`message 说明结果行数不足
#### Scenario: result JSONPath 校验
- **WHEN** db target 查询返回首行 `{status: "active"}` 且配置 `expect.result: [{json: {path: "$.rows[0].status", equals: "active"}}]`
- **THEN** 系统 SHALL 基于 `{rows, rowCount}` 结果对象执行 JSONPath并判定 result 阶段通过
#### Scenario: result rowCount 校验
- **WHEN** db target 查询返回 2 行且配置 `expect.result: [{json: {path: "$.rowCount", equals: 2}}]`
- **THEN** 系统 SHALL 判定 result 阶段通过
#### Scenario: 无 query 时结果类 expect 被忽略
- **WHEN** db target 未配置 `db.query` 但配置了 `expect.rowCount``expect.rows``expect.result`
- **THEN** 系统 SHALL 忽略这些查询结果断言(仅 `durationMs` 生效)
#### Scenario: 快速失败顺序
- **WHEN** db target 同时配置 durationMs、rowCount、rows 和 result
- **THEN** 系统 SHALL 按 durationMs → rowCount → rows → result 顺序校验,任一阶段失败立即返回
### Requirement: db checker 启动期配置校验
系统 SHALL 在启动期对 db checker 的配置契约和语义执行严格校验。Db target 的 `db` 分组 SHALL 只允许 `url``query` 字段。Db expect SHALL 只允许 `durationMs``rowCount``rows``result` 字段。未知字段、非法 matcher、非法 ContentRules、非法 regex 和 ReDoS 风险正则 MUST 导致启动期配置错误。
#### Scenario: db expect durationMs 非法
- **WHEN** YAML 中 db target 配置 `expect.durationMs` 不是合法 `ValueMatcher`
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.durationMs 格式错误
#### Scenario: db expect rowCount 非法
- **WHEN** YAML 中 db target 配置 `expect.rowCount` 不是合法 `ValueMatcher`
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.rowCount 格式错误
#### Scenario: db expect rows 非法
- **WHEN** YAML 中 db target 配置 `expect.rows` 不是对象数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.rows 必须为对象数组
#### Scenario: db expect rows 元素列值非法
- **WHEN** YAML 中 db target 配置 `expect.rows: [{ cnt: { foo: 1 } }]`,其中 foo 不是合法 matcher
- **THEN** 系统 SHALL 以配置错误退出,提示 rows 中包含未知 matcher
#### Scenario: db expect result 非法
- **WHEN** YAML 中 db target 配置 `expect.result` 不是合法 ContentRules 数组
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.result 格式错误
#### Scenario: db expect 未知字段失败
- **WHEN** YAML 中 db target 的 expect 包含 `status: [200]``maxDurationMs: 1000` 或其他非 db expect 字段
- **THEN** 系统 SHALL 以配置错误退出,提示 expect 包含未知字段
#### Scenario: db expect rows 中 regex 正则非法
- **WHEN** YAML 中 db target 配置 `expect.rows: [{ name: { regex: "[invalid" } }]`
- **THEN** 系统 SHALL 在启动期配置校验失败,而不是延迟到运行期抛错