Files
AskaEth afe9afb1b5 feat(events): 渠道事件桥接接线 + 组合根(design/26 E3+E4)
- E3:channelbridge/events.go 唯一插入点 recordEvent(两轴映射 Category→Tier、摘要恒过 SanitizeNoticeText、角色/账号只认白名单)+ Options.EventStore 注入
  - 未接线 store=nil ⇒ 内存计数 + 首次 DEBUG,绝不中断入站(变异实测:改成直接调 Record ⇒ panic,测试红)
  - 普通聊天消息零副作用(变异:去掉 Applicable 早退 ⇒ rows=1 红)
  - T1 遥测只计数不落行(变异:心跳误判 T2 ⇒ 「逐条落行 1 行,want 0」红)
- E4:wire_channel_events.go(启动期清扫 + 双 ticker + 退出 flush,逐字对齐 wire_document_gc 的三条取舍)、wire_channels 注入、main.go 加一行 startChannelEvents
- internal/config/duration_env.go:新 env 键的读取口径(进程环境 > .env > 默认;「没写」与「写了空」都当没配;非法值回落 + 报错)——避免「只写在 .env 里被静默忽略」
- 三个新 env 键:CHANNEL_EVENT_RETENTION / GC_INTERVAL / COUNTER_FLUSH(模板同批更新,测试钉住键名一致)
- 插入点比设计示意图晚一步(放 preEntryReview 之后,只归一化一次且 NoticeClass 已有结论),「留存无条件、在任何早退之前」这条性质不变
2026-10-05 14:10:24 +08:00

109 lines
4.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package config
// 本文件覆盖 LoadDurationEnv(切片 E3+E4 的 CHANNEL_EVENT_* 读取口径):三条判据
// 各自的用例 —— **未配置回落默认**、**`.env` 只写在文件里也真实生效**(这正是不能用
// os.Getenv 的原因)、**配了但读不懂 ⇒ 回落默认 + 报错**(绝不静默失效)。
//
// 与 owner_identity_test.go 同一约定:读进程环境 / 写 .env 的用例**不并行**
// (unsetEnvForTest 会改动进程环境,与并行读取互相干扰)。
import (
"path/filepath"
"testing"
"time"
)
// TestLoadDurationEnv_未配置回落默认_正常:键既不在进程环境也不在 .env ⇒ 返回默认值、
// 不报错;值为空白(`KEY=`)同样按「没配」处理。
func TestLoadDurationEnv_未配置回落默认_正常(t *testing.T) {
const key = "CYRENE_TEST_DURATION_UNSET"
unsetEnvForTest(t, key)
value, err := LoadDurationEnv("", key, 720*time.Hour)
if err != nil {
t.Fatalf("未配置时不该报错:%v", err)
}
if value != 720*time.Hour {
t.Fatalf("未配置时取值 = %v, want 720h(默认)", value)
}
blank := writeDotEnv(t, key+"=")
value, err = LoadDurationEnv(blank, key, time.Hour)
if err != nil {
t.Fatalf("空白取值不该报错:%v", err)
}
if value != time.Hour {
t.Fatalf("空白取值时 = %v, want 1h(按未配置处理)", value)
}
}
// TestLoadDurationEnv_进程环境优先_正常:优先级与其余配置一致(进程环境 > .env > 默认)。
func TestLoadDurationEnv_进程环境优先_正常(t *testing.T) {
const key = "CYRENE_TEST_DURATION_PRECEDENCE"
t.Setenv(key, "45m")
value, err := LoadDurationEnv(writeDotEnv(t, key+"=3h"), key, 30*time.Second)
if err != nil {
t.Fatalf("LoadDurationEnv: %v", err)
}
if value != 45*time.Minute {
t.Fatalf("取值 = %v, want 45m(进程环境优先于 .env)", value)
}
}
// TestLoadDurationEnv_只写在env文件里也生效_正常:这是本函数存在的理由 —— `.env` 不写回
// 进程环境,os.Getenv 会**静默忽略**它,而本函数必须读到(否则照模板部署的新实例漏配且
// 静默失效,AGENTS §10 的 E6 条目)。显式 0 与负值也必须**原样抵达**:渠道事件 GC 正是
// 靠 ≤0 判「显式关闭」(design/26 §4.4)。
func TestLoadDurationEnv_只写在env文件里也生效_正常(t *testing.T) {
const key = "CYRENE_TEST_DURATION_DOTENV"
unsetEnvForTest(t, key)
zero, err := LoadDurationEnv(writeDotEnv(t, "# 注释行", key+"=0"), key, 720*time.Hour)
if err != nil {
t.Fatalf("LoadDurationEnv(0): %v", err)
}
if zero != 0 {
t.Fatalf("取值 = %v, want 0(.env 里的显式 0 必须原样抵达)", zero)
}
neg, err := LoadDurationEnv(writeDotEnv(t, key+"=-1h"), key, time.Hour)
if err != nil {
t.Fatalf("LoadDurationEnv(负值): %v", err)
}
if neg != -time.Hour {
t.Fatalf("负值 = %v, want -1h(负值必须原样抵达,不得被当成默认)", neg)
}
}
// TestLoadDurationEnv_非法取值回落默认并报错_异常:配了但读不懂 ⇒ 返回默认值 **且**返回
// 错误(调用方据此记 WARN 并继续),绝不静默失效。
func TestLoadDurationEnv_非法取值回落默认并报错_异常(t *testing.T) {
const key = "CYRENE_TEST_DURATION_INVALID"
unsetEnvForTest(t, key)
value, err := LoadDurationEnv(writeDotEnv(t, key+"=一小时"), key, 30*time.Second)
if err == nil {
t.Fatal("非法 duration 必须报错(AGENTS §10:非法配置不许静默失效)")
}
if value != 30*time.Second {
t.Fatalf("非法取值时的回落值 = %v, want 30s", value)
}
}
// TestLoadDurationEnv_env文件不存在也不报错_边界:路径为空(不看 .env)与路径指向不存在的
// 文件都不该让启动失败 —— 三个键都是可选旋钮。⚠️ 路径非空但文件缺失时 parseDotEnv 的行为
// 由既有约定决定(缺失不算错误),本用例把它钉在「返回默认值」这一侧。
func TestLoadDurationEnv_env文件不存在也不报错_边界(t *testing.T) {
const key = "CYRENE_TEST_DURATION_MISSING_DOTENV"
unsetEnvForTest(t, key)
value, err := LoadDurationEnv(filepath.Join(t.TempDir(), "absent.env"), key, time.Hour)
if err != nil {
t.Fatalf("缺失的 .env 不该让读取失败:%v", err)
}
if value != time.Hour {
t.Fatalf("取值 = %v, want 1h(默认)", value)
}
}