mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-26 12:23:23 +00:00
fix(test): 测试不再抢生产端口 :8080(internal/plugins 加载内置 webui 所致)
部署过程中反复出现「8080 被 plugins.test 占用」导致生产 WebUI 起不来。 追到底:internal/plugins 的集成测试会 pluginReg.Load(全部内置插件), 其中 webui 默认监听 :8080 —— **正是生产实例的端口**。 ## 为什么这个 bug 特别难查 它不是测试失败,而是**测试与生产静默抢端口**:先到者胜,另一个 bind 失败。 - 跑测试的人看到「测试随机失败」(其实是生产先占了) - 用生产的人看到「WebUI 随机死掉」(其实是测试先占了) - 两边现象互不相干,且各自单独重跑往往都过 叠加 webui 已有的「bind 失败必须显式报错」修复后,症状从「静默死亡」 变成「随机报错」,这反而让归属更容易看错 —— 我一开始也是先怀疑自己的 部署脚本,直到采样 /proc/<pid>/cwd 才确认是测试进程。 ## 修法 集成测试在 Load 之前用既有的 SetListenOverride 把地址指到 127.0.0.1:0(内核分配空闲端口),并在 cleanup 还原。 测试因此拿到真实可用的 HTTP 服务,且与任何固定端口实例完全隔离。 - webui 新增 ListenOverride() 读取当前值,供调用方保存/还原 (只有 setter 时无法在不破坏调用方状态的前提下做临时覆盖)。 ## 验证 - 修复前:跑 ./internal/plugins/ 期间 8080 持续归 plugins.test(109/200 采样) - 修复后:35 次采样全程 8080 归 homed,测试同时全绿 - 变异验证:移除 override 后立刻复现抢端口,判据有效 另记两个测试卫生问题(同一根源,已顺手清理泄漏进程): 测试会启动**真实插件进程**(/home/newqqagent/plugins/*/plugin.bin)。 kill 测试进程后这些子进程会残留。已全部清理,生产 23 插件恢复正常。
This commit is contained in:
@ -39,6 +39,20 @@ func setupIntegration(t *testing.T) *testPluginEnv {
|
||||
func setupIntegrationWithProvider(t *testing.T, pm *agentAPI.ProviderManager) *testPluginEnv {
|
||||
t.Helper()
|
||||
|
||||
// 测试绝不能绑生产端口。这里加载的是**全部内置插件**(含 webui),
|
||||
// 而 webui 默认监听 :8080 —— 那正是生产实例的端口。
|
||||
// 不覆盖的后果不是测试失败,而是**测试静默地跟生产抢端口**:
|
||||
// 先到者胜,另一个 bind 失败。webui 现在会在 bind 失败时明确报错,
|
||||
// 于是表现为「测试随机失败」+「生产 WebUI 随机死掉」,且两边看起来
|
||||
// 互不相干,极难定位(实际踩到过)。
|
||||
//
|
||||
// 用 SetListenOverride 指到 127.0.0.1:0(内核分配空闲端口):
|
||||
// 测试拿到真实可用的 HTTP 服务,且与任何固定端口实例互不干扰。
|
||||
if prev := webui.ListenOverride(); prev == "" {
|
||||
webui.SetListenOverride("127.0.0.1:0")
|
||||
t.Cleanup(func() { webui.SetListenOverride(prev) })
|
||||
}
|
||||
|
||||
tmpDir, err := os.MkdirTemp("", "hc_integration_*")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@ -68,10 +68,17 @@ var listenOverride string
|
||||
|
||||
// SetListenOverride 设置监听地址覆盖(空值表示不覆盖)。
|
||||
// 由 cmd/homed 在插件加载前调用,见 resolveWebUIOverride。
|
||||
//
|
||||
// 测试也用它在加载内置插件前把地址指到 127.0.0.1:0:
|
||||
// 否则测试会绑生产端口 :8080,与线上实例互相抢(见 integration_test.go)。
|
||||
func SetListenOverride(addr string) {
|
||||
listenOverride = strings.TrimSpace(addr)
|
||||
}
|
||||
|
||||
// ListenOverride 返回当前的覆盖值(空串表示未覆盖)。
|
||||
// 供调用方「保存-还原」用,避免测试互相污染。
|
||||
func ListenOverride() string { return listenOverride }
|
||||
|
||||
// resolveListenAddr 决定最终监听地址:覆盖值 > 插件设置 > 内置默认。
|
||||
// 抽成纯函数是为了能被单测直接钉住优先级。
|
||||
func resolveListenAddr(setting string) string {
|
||||
|
||||
Reference in New Issue
Block a user