test(testhealth): 替身竞态加锁 + 墙钟断言硬度(M33)
四处测试健康债务,只改 *_test.go,不动生产代码、不降并发: - channelbridge:stubChatter / stubSessions 的跨 goroutine 字段一律经 mu 访问 (Run/GetOrCreate 在车道 worker 上写、测试 goroutine 读,两者无 happens-before; 负向断言「等一会儿再看循环有没有被驱动」尤其如此)。读写走访问器,Messages() 返回副本;t.Parallel 与并发度不变。 - plugins/tools/io:claimProbeTimeout 2s(真实时间预算)→ 60s,并由 claimProbeWait 按 t.Deadline 收缩。探针只等 goroutine 被调度(无时间语义),放大余量把 「机器快慢」从断言里去掉,死锁仍以断言失败暴露。 - backthink:TestSelfWakeGate_WindowExpiry 窗口 120ms → 6s(给 waitFor 的 4s 上界 留 2s 余量),到期等待改为按首次受理时刻推算 window+250ms,不再盲睡 3×窗口。 另修 TestSelfWakeStatus_MatchesReceiptAndTracksPendingSlot:worker 先 take 再进 Think,卡 Think 并不占待跑槽 —— 改为「上一轮把 worker 占住再断言 Pending」。 - memory:墙钟实测用例显式给闸 5s 预算(measureGateBudget),不再因默认 150ms 超时 fail-open 打炸「每轮都真扫真判」前置断言;并把 GateFailed 纳入该断言。
This commit is contained in:
1 parent
da6a365222
commit
7d9b2132bb
18 files changed
+407
-242
No files matched your search
@@ -20,9 +20,38 @@ import (
|
||||
// 带闸门的工具包装、以及等待与断言助手。夹具只搭台子,不写断言语义 —— 读共享 / 写独占的
|
||||
// 判定一律由**真实的**进程内占用表给出(tool.NewFileClaimer),不拿自造的假表去测。
|
||||
|
||||
// claimProbeTimeout 是「第一路必须进入闸门 / 一路必须结束」这类断言的等待上限:足够宽
|
||||
// 以免依赖机器速度,又足够短以免偶发死锁拖成整包超时。
|
||||
const claimProbeTimeout = 2 * time.Second
|
||||
// claimProbeTimeout 是「第一路必须进入闸门 / 一路必须结束」这类断言的等待上限。
|
||||
//
|
||||
// 这些等待**不含时间语义**:runLeg 起的那一路只要被调度到,就会立刻 close(entered)
|
||||
// 或把结果写进 chan ——「等多久」与被测行为无关,唯一要防的是真死锁时永远等下去。
|
||||
// 旧值 2s 却是一个**真实时间预算**:73 个测试包并行抢核时,一个刚起的 goroutine 被
|
||||
// 饿上几秒并非不可想象(本轮其他证人据此报过假红;本机 12 核上 4 路并发 + 全树并行
|
||||
// 压测未复现,故按余量加固,不拿复现驱动)。
|
||||
//
|
||||
// 现取值:默认 60s,即旧值的 30 倍余量(与「整树并行」量级相称:正常调度是微秒级,
|
||||
// 需要 60s 才轮到调度意味着机器已经不可用);同时由 claimProbeWait 按 t.Deadline
|
||||
// 的剩余预算收缩,真死锁仍以**断言失败**暴露,不会拖成整包超时。
|
||||
const claimProbeTimeout = 60 * time.Second
|
||||
|
||||
// claimProbeFloor 是探针等待的下限:即使已经接近 t.Deadline,也至少等这么久再判失败
|
||||
// (「断言失败 + 原因」比「整包超时」可读得多)。
|
||||
const claimProbeFloor = 5 * time.Second
|
||||
|
||||
// claimProbeWait 返回本次探针的等待上限:默认 claimProbeTimeout,接近 t.Deadline 时
|
||||
// 收缩到「剩余预算的一半」,使等待永远发生在包超时之内。
|
||||
func claimProbeWait(t *testing.T) time.Duration {
|
||||
t.Helper()
|
||||
wait := claimProbeTimeout
|
||||
if dl, ok := t.Deadline(); ok {
|
||||
if half := time.Until(dl) / 2; half < wait {
|
||||
wait = half
|
||||
}
|
||||
}
|
||||
if wait < claimProbeFloor {
|
||||
wait = claimProbeFloor
|
||||
}
|
||||
return wait
|
||||
}
|
||||
|
||||
// legResult 是一路调用的结果。
|
||||
type legResult struct {
|
||||
@@ -228,7 +257,7 @@ func awaitEnter(t *testing.T, ch <-chan struct{}) {
|
||||
t.Helper()
|
||||
select {
|
||||
case <-ch:
|
||||
case <-time.After(claimProbeTimeout):
|
||||
case <-time.After(claimProbeWait(t)):
|
||||
t.Fatal("第一路没有进入执行")
|
||||
}
|
||||
}
|
||||
@@ -239,7 +268,7 @@ func awaitDone(t *testing.T, ch <-chan legResult) legResult {
|
||||
select {
|
||||
case res := <-ch:
|
||||
return res
|
||||
case <-time.After(claimProbeTimeout):
|
||||
case <-time.After(claimProbeWait(t)):
|
||||
t.Fatal("这一路没有结束")
|
||||
return legResult{}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user