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:
AskaEth committed 2026-10-24 22:24:14 +08:00
1 parent da6a365222
commit 7d9b2132bb
18 files changed
+407 -242

No files matched your search

@@ -102,8 +102,8 @@ func TestColdShoulderPrecedesAddressedToMe(t *testing.T) {
b.process(context.Background(), coldShoulderMention("减少文本输出量"))
if chat.sessionID != "" {
t.Fatalf("循环被驱动 = %q, want \"\"(冷避必须先于 @她必回)", chat.sessionID)
if chat.SessionID() != "" {
t.Fatalf("循环被驱动 = %q, want \"\"(冷避必须先于 @她必回)", chat.SessionID())
}
recs := hist.records()
if len(recs) != 1 || recs[0].Content != "减少文本输出量" {
@@ -137,21 +137,21 @@ func TestColdShoulderSecondReportedPhraseAndCooldownWindow(t *testing.T) {
}
b.process(context.Background(), coldShoulderMention("在本群中文本输出调到最少"))
if chat.sessionID != "" {
t.Fatalf("原话②之后循环被驱动 = %q, want \"\"", chat.sessionID)
if chat.SessionID() != "" {
t.Fatalf("原话②之后循环被驱动 = %q, want \"\"", chat.SessionID())
}
// 冷却期内:普通 @她 也不回(冷避优先于「@她必回」)。
b.process(context.Background(), coldShoulderMention("晚上有空吗"))
if chat.sessionID != "" {
t.Fatalf("冷却期内 @她 被驱动 = %q, want \"\"(@ 不得作废冷避)", chat.sessionID)
if chat.SessionID() != "" {
t.Fatalf("冷却期内 @她 被驱动 = %q, want \"\"(@ 不得作废冷避)", chat.SessionID())
}
// 推过默认冷却时长(30 分钟):她恢复到「@她必回」的常态。
now = now.Add(defaultCooldownDuration + time.Minute)
b.process(context.Background(), coldShoulderMention("晚上有空吗"))
if chat.sessionID != "sess-g" {
t.Fatalf("冷却过期后 @她 仍未回:session = %q, want sess-g(冷避是**有时限**的)", chat.sessionID)
if chat.SessionID() != "sess-g" {
t.Fatalf("冷却过期后 @她 仍未回:session = %q, want sess-g(冷避是**有时限**的)", chat.SessionID())
}
}
@@ -172,15 +172,15 @@ func TestColdShoulderNormalMentionNotCooled(t *testing.T) {
}
b.process(context.Background(), coldShoulderMention("晚上有空吗"))
if chat.sessionID != "sess-g" {
t.Fatalf("普通 @她 被拦下了:session = %q, want sess-g", chat.sessionID)
if chat.SessionID() != "sess-g" {
t.Fatalf("普通 @她 被拦下了:session = %q, want sess-g", chat.SessionID())
}
// 第二条紧接着的普通 @她:若第一条被误判成负面态度,这条会落进冷却而静默。
chat.sessionID = ""
chat.clearSessionID()
b.process(context.Background(), coldShoulderMention("在不在"))
if chat.sessionID != "sess-g" {
t.Fatalf("第二条普通 @她 未回:session = %q(首条被误冷却了吗)", chat.sessionID)
if chat.SessionID() != "sess-g" {
t.Fatalf("第二条普通 @她 未回:session = %q(首条被误冷却了吗)", chat.SessionID())
}
}
@@ -214,8 +214,8 @@ func TestColdShoulderGroupOnlyBoundaries(t *testing.T) {
Content: "闭嘴", ContentType: adapter.ContentText,
})
if chat.sessionID != "sess-p" {
t.Fatalf("陌生人私聊被冷避拦下:session = %q, want sess-p(冷避是群机制)", chat.sessionID)
if chat.SessionID() != "sess-p" {
t.Fatalf("陌生人私聊被冷避拦下:session = %q, want sess-p(冷避是群机制)", chat.SessionID())
}
})
@@ -237,8 +237,8 @@ func TestColdShoulderGroupOnlyBoundaries(t *testing.T) {
m.Content = "闭嘴"
b.process(context.Background(), m)
if chat.sessionID != history.MainSessionID {
t.Fatalf("主人私聊被冷避拦下:session = %q, want %q", chat.sessionID, history.MainSessionID)
if chat.SessionID() != history.MainSessionID {
t.Fatalf("主人私聊被冷避拦下:session = %q, want %q", chat.SessionID(), history.MainSessionID)
}
})
@@ -251,8 +251,8 @@ func TestColdShoulderGroupOnlyBoundaries(t *testing.T) {
b.process(context.Background(), ownerLaneGroupMsg("安静点", adapter.Mention{UserID: "10001"}))
if chat.sessionID != "sess-og" {
t.Fatalf("主人群 @她 被冷避拦下:session = %q, want sess-og(owner 车道不受冷避影响)", chat.sessionID)
if chat.SessionID() != "sess-og" {
t.Fatalf("主人群 @她 被冷避拦下:session = %q, want sess-og(owner 车道不受冷避影响)", chat.SessionID())
}
})
}
@@ -279,8 +279,8 @@ func TestColdShoulderSilencedMessageStillEntersContext(t *testing.T) {
}
b.process(context.Background(), coldShoulderMention("减少文本输出量"))
if chat.sessionID != "" {
t.Fatalf("循环被驱动 = %q, want \"\"", chat.sessionID)
if chat.SessionID() != "" {
t.Fatalf("循环被驱动 = %q, want \"\"", chat.SessionID())
}
// ① 静默那条已被登记(不是被丢掉)。
@@ -297,11 +297,11 @@ func TestColdShoulderSilencedMessageStillEntersContext(t *testing.T) {
// ② 冷却过期后 @她 驱动回合 → 该回合上下文里读得到那条被静默的话。
now = now.Add(defaultCooldownDuration + time.Minute)
b.process(context.Background(), coldShoulderMention("在吗"))
if chat.sessionID != "sess-g" {
t.Fatalf("冷却过期后 @她 未驱动回合:session = %q", chat.sessionID)
if chat.SessionID() != "sess-g" {
t.Fatalf("冷却过期后 @她 未驱动回合:session = %q", chat.SessionID())
}
if !loopMessagesContain(chat.messages, "减少文本输出量") {
t.Fatalf("被静默登记的消息没进上下文:%+v", chat.messages)
if !loopMessagesContain(chat.Messages(), "减少文本输出量") {
t.Fatalf("被静默登记的消息没进上下文:%+v", chat.Messages())
}
}