mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-02 23:33:58 +00:00
test(seq): 三个压力测试 —— 超长序列 / 100 工具并行 / 串行降级
与单元判据的分工:单元判据钉住**语义**(一条路径对不对);压力测试钉住
**规模下的不变量**。沿用仓内既有范式(media/soak_test.go):
testing.Short() 跳过 + 独立 -run 跑。
① 超长序列
· 解析 10 / 100 / 1000 组(250KB 文本):6.8ms,无硬上限误报
· 执行 200 组 × 5 工具 = 1000 次调用:2.0ms
断言:每工具恰好被调 nGroups 次(无遗漏/重复)、结果含**最后一组**
—— 组间串行在规模下仍成立
② 100 工具组内并行
· 100 工具全声明并发安全 ⇒ 11ms,完成顺序**确实被打乱**(判据会校验
这一点,否则它测不到并发)
· 断言每个槽拿到**自己**的结果(并发下若按完成顺序合并就会错位)
③ 串行降级
· 50 个工具里**一个**未声明并发安全 ⇒ 整批退回串行,
完成顺序严格等于声明序(106ms vs 并发的 11ms,降级确实生效)
★ 压力测试第一次跑就抓到一个**真实分层缺陷**:
「含非并发安全工具则整批串行」这条规则**只在上层 runGroup 实现**,
而引擎层 execGroup 只信 g.Parallel 字段 ⇒ 任何人直接调 execGroup
都会拿到不受约束的并发。
已修:降级判据下沉到引擎层,新增 batchCanRun(g, runner),
toolRunner 增加 parallelSafe 方法(生产路径行为不变,只是把判据
放到了它本该在的层)。
过程中压测自身也暴露了两个测试缺陷(都修了):
· fixture 让 100 个工具写同一个标量槽 o,被静态校验正确拦下
("组内并行下同名写入是数据竞争")—— 压测不该去撞这条规则;
· ★ e2eRunner.called 是无锁 append,100 工具并发时 -race 报出**真竞态**
(不是误报)—— 加锁 + 提供 calledSnapshot 供断言。
另:建序列与跑序列原本用了**不同 plugin 实例**(序列存在实例的 store 里,
换实例就读不到自己刚建的),已改为同一实例。
回归:go test -race ./internal/plugins/seq 全绿;go test ./internal/... 全绿。
This commit is contained in:
@ -17,6 +17,29 @@ import (
|
||||
// 插值判据就成了摆设——它永远"通过")。
|
||||
type toolRunner interface {
|
||||
call(name string, args map[string]interface{}) (string, error)
|
||||
// parallelSafe 报告工具是否**声明**可并发。
|
||||
//
|
||||
// ⚠️ 引擎层(execGroup)必须有它:否则"含非并发安全工具则整批串行"
|
||||
// 这条规则只在上层(runGroup)实现 —— 任何人直接调 execGroup 都会
|
||||
// 拿到不受约束的并发。压力测试 TestStress_ParallelNotSafeFallsBackToSerial
|
||||
// 正是为此而写(它第一次跑就抓到了这个分层缺陷)。
|
||||
parallelSafe(name string) bool
|
||||
}
|
||||
|
||||
// batchCanRun 并发执行本组工具的判据。
|
||||
//
|
||||
// 规则:**全部**工具都声明并发安全才并发;一个不安全就**整批**串行。
|
||||
// 不做部分并发 —— 收益不抵其不可预测性。
|
||||
func batchCanRun(g Group, runner toolRunner) bool {
|
||||
if !g.Parallel || len(g.Tools) <= 1 || runner == nil {
|
||||
return false
|
||||
}
|
||||
for _, t := range g.Tools {
|
||||
if !runner.parallelSafe(t.Tool) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// errToolNotFound 表示「工具不存在」(未注册 / 插件未加载、已卸载或崩溃)。
|
||||
@ -83,7 +106,7 @@ func execGroup(g Group, args map[string]interface{}, runner toolRunner) (GroupRe
|
||||
}
|
||||
|
||||
// ② 执行
|
||||
if g.Parallel && n > 1 {
|
||||
if batchCanRun(g, runner) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < n; i++ {
|
||||
wg.Add(1)
|
||||
|
||||
Reference in New Issue
Block a user