feat: 新增 DB checker — 支持 PostgreSQL/MySQL/SQLite 连接测试与 SQL 查询断言
- 实现 db 类型 checker,使用 Bun 内置 SQL 类 - 支持 db.url 连接字符串和可选 db.query 查询语句 - expect 支持 maxDurationMs、rowCount、rows 逐列校验 - 凭据屏蔽序列化输出 - SQLite 内存数据库测试覆盖
This commit is contained in:
141
openspec/specs/db-checker/spec.md
Normal file
141
openspec/specs/db-checker/spec.md
Normal file
@@ -0,0 +1,141 @@
|
||||
## 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,包括 `maxDurationMs`、`rowCount` 和 `rows`,按 duration、rowCount、rows 的阶段顺序快速失败。
|
||||
|
||||
#### Scenario: maxDurationMs 校验
|
||||
- **WHEN** db target 配置 `expect.maxDurationMs: 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 按索引匹配列值(operator 形式)
|
||||
- **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: 无 query 时 expect 被忽略
|
||||
- **WHEN** db target 未配置 `db.query` 但配置了 `expect.rowCount`
|
||||
- **THEN** 系统 SHALL 忽略 expect 中的 rowCount 和 rows 断言(仅 maxDurationMs 生效)
|
||||
|
||||
#### Scenario: 快速失败顺序
|
||||
- **WHEN** db target 同时配置 maxDurationMs、rowCount 和 rows
|
||||
- **THEN** 系统 SHALL 按 duration → rowCount → rows 顺序校验,任一阶段失败立即返回
|
||||
|
||||
### Requirement: db checker 启动期配置校验
|
||||
系统 SHALL 在启动期对 db checker 的配置契约和语义执行严格校验。Db target 的 `db` 分组 SHALL 只允许 `url` 和 `query` 字段。Db expect SHALL 只允许 `maxDurationMs`、`rowCount` 和 `rows` 字段。
|
||||
|
||||
#### Scenario: db expect maxDurationMs 非法
|
||||
- **WHEN** YAML 中 db target 配置 `expect.maxDurationMs` 不是非负有限数字
|
||||
- **THEN** 系统 SHALL 以配置错误退出,提示 expect.maxDurationMs 格式错误
|
||||
|
||||
#### Scenario: db expect rowCount 非法
|
||||
- **WHEN** YAML 中 db target 配置 `expect.rowCount` 不是合法的 operator 对象
|
||||
- **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 不是合法 operator
|
||||
- **THEN** 系统 SHALL 以配置错误退出,提示 rows 中包含未知 operator
|
||||
|
||||
#### Scenario: db expect 未知字段失败
|
||||
- **WHEN** YAML 中 db target 的 expect 包含 `status: [200]` 或其他非 db expect 字段
|
||||
- **THEN** 系统 SHALL 以配置错误退出,提示 expect 包含未知字段
|
||||
|
||||
#### Scenario: db expect rows 中 match 正则非法
|
||||
- **WHEN** YAML 中 db target 配置 `expect.rows: [{ name: { match: "[invalid" } }]`
|
||||
- **THEN** 系统 SHALL 在启动期配置校验失败,而不是延迟到运行期抛错
|
||||
@@ -1,11 +1,11 @@
|
||||
## Purpose
|
||||
|
||||
定义 HTTP 拨测工具的 YAML 配置文件格式、解析校验规则和 CLI 启动流程。
|
||||
定义拨测工具的 YAML 配置文件格式、解析校验规则和 CLI 启动流程。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: YAML 配置文件格式
|
||||
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、runtime 配置、checker 默认值和 typed target 列表(含可选 group 字段)。target MUST 使用 `type` 字段声明 checker 类型,HTTP 领域字段 MUST 放在 `http` 分组,cmd 领域字段 MUST 放在 `cmd` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`(非负整数)字段。
|
||||
系统 SHALL 支持通过 YAML 配置文件定义全部运行参数,包括 server 配置、runtime 配置、checker 默认值和 typed target 列表(含可选 group 字段)。target MUST 使用 `type` 字段声明 checker 类型,HTTP 领域字段 MUST 放在 `http` 分组,cmd 领域字段 MUST 放在 `cmd` 分组,db 领域字段 MUST 放在 `db` 分组。HTTP target 的 `http` 分组 SHALL 支持可选的 `ignoreSSL`(布尔值)和 `maxRedirects`(非负整数)字段。Db target 的 `db` 分组 SHALL 支持 `url`(必填)和 `query`(可选)字段。
|
||||
|
||||
#### Scenario: 完整配置文件解析
|
||||
- **WHEN** 系统启动并读取包含 server、runtime、defaults、targets(含 group 字段)的 YAML 配置文件
|
||||
@@ -31,6 +31,10 @@
|
||||
- **WHEN** YAML 配置中 HTTP target 设置 `http.maxRedirects: 5`
|
||||
- **THEN** 系统 SHALL 解析该字段并在执行时允许最多跟随 5 次重定向
|
||||
|
||||
#### Scenario: 最简 db 配置文件解析
|
||||
- **WHEN** 系统读取只包含一个 `type: db` target 和 `db.url` 的 YAML 配置文件
|
||||
- **THEN** 系统 SHALL 使用内置默认值填充未指定的字段(interval=30s, timeout=10s, group="default")
|
||||
|
||||
### Requirement: CLI 参数
|
||||
系统 SHALL 通过单一命令行参数接受 YAML 配置文件路径。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user