gcli2api / internal /server /cache_stats_test.go
a3216's picture
chore: 同步到上游 1.12.0-panel + 凭证同步/独立启动器/保活
6d60378 verified
Raw History Blame Contribute Delete
3.26 kB
// cache_stats_test.go 钉住缓存命中率观测链路(issue #92):SSE 末帧的
// prompt_cache_hit/miss_tokens 采集,以及「曾命中却整段未命中」的 WARN 信号判据。
package server
import (
"strings"
"testing"
"time"
)
func feedStatsLines(s *chatStatsReader, lines ...string) {
for _, l := range lines {
s.parseSSELine(l)
}
}
// 流式末帧带 hit/miss:CacheTokens 原样返回;只带 hit 时 miss 按 prompt-hit 推导;
// 上游完全没回缓存维度时 ok=false(不参与统计)。
func TestStatsReaderCacheTokens(t *testing.T) {
s := newChatStatsReaderSince(strings.NewReader(""), time.Now())
feedStatsLines(s,
`data: {"usage":{"prompt_tokens":1000,"completion_tokens":5,"total_tokens":1005,"credit":0.1,"prompt_cache_hit_tokens":900,"prompt_cache_miss_tokens":100}}`,
)
if hit, miss, ok := s.CacheTokens(); !ok || hit != 900 || miss != 100 {
t.Fatalf("hit=%d miss=%d ok=%v, want 900/100/true", hit, miss, ok)
}
s2 := newChatStatsReaderSince(strings.NewReader(""), time.Now())
feedStatsLines(s2,
`data: {"usage":{"prompt_tokens":8500,"prompt_cache_hit_tokens":8400}}`,
)
if hit, miss, ok := s2.CacheTokens(); !ok || hit != 8400 || miss != 100 {
t.Fatalf("derived miss: hit=%d miss=%d ok=%v, want 8400/100/true", hit, miss, ok)
}
s3 := newChatStatsReaderSince(strings.NewReader(""), time.Now())
feedStatsLines(s3,
`data: {"usage":{"prompt_tokens":100,"completion_tokens":5}}`,
)
if _, _, ok := s3.CacheTokens(); ok {
t.Fatal("无缓存字段应 ok=false")
}
}
// WARN 信号状态机:先命中、再大前缀整段未命中 → 触发一次;冷却内重复未命中
// 不再触发;从未命中的模型(首请求天然全 miss)与小前缀不触发。
func TestCacheMissSignal(t *testing.T) {
old := cacheMissWarnEvery
cacheMissWarnEvery = time.Hour // 拉长冷却,验证「冷却内不重复」
t.Cleanup(func() {
cacheMissWarnEvery = old
cacheMissWarn = &cacheMissSignal{everHit: map[string]bool{}, last: map[string]time.Time{}}
})
cacheMissWarn = &cacheMissSignal{everHit: map[string]bool{}, last: map[string]time.Time{}}
cacheMissWarn.noteCacheTokens("glm-5.3", 8500, 8000, 500) // 命中 → 标记可命中
if cacheMissWarn.last["glm-5.3"] != (time.Time{}) {
t.Fatal("命中不应触发 WARN")
}
cacheMissWarn.noteCacheTokens("glm-5.3", 8500, 0, 8500) // 整段未命中 → 触发
if cacheMissWarn.last["glm-5.3"].IsZero() {
t.Fatal("曾命中的模型整段未命中应触发 WARN 记录")
}
first := cacheMissWarn.last["glm-5.3"]
cacheMissWarn.noteCacheTokens("glm-5.3", 8500, 0, 8500) // 冷却内 → 不重复
if !cacheMissWarn.last["glm-5.3"].Equal(first) {
t.Fatal("冷却期内不应重复触发")
}
// 从未命中的模型(新模型首请求天然全 miss)不触发。
cacheMissWarn.noteCacheTokens("new-model", 5000, 0, 5000)
if !cacheMissWarn.last["new-model"].IsZero() {
t.Fatal("从未命中的模型不应触发")
}
// 小前缀不触发。
cacheMissWarn.noteCacheTokens("glm-5.3", 500, 0, 500)
// miss 缺失(上游只回 hit=0、无 miss、无 prompt)不触发。
cacheMissWarn.noteCacheTokens("glm-5.3", 0, 0, 0)
}