From 99914a9e9b60eed093a3695e3b6f44acab4d5cbe Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 19 Oct 2026 15:23:23 +0800 Subject: [PATCH] =?UTF-8?q?test(plugins):=20=E5=8A=A0=E8=B4=9F=E5=90=91?= =?UTF-8?q?=E6=96=AD=E8=A8=80=E5=AE=88=E6=8A=A4=20timer=20=E4=B8=8D?= =?UTF-8?q?=E5=86=8D=E8=A2=AB=E6=B3=A8=E5=86=8C=E8=BF=9B=E5=86=85=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit timer 已移出内置插件(717054a),但原有 TestIntegrationAllPluginsRegister 只是正向清单 —— 它断言「该有的工具都在」,对「多出来」是瞎的: 把 internal/plugins/timer 与 all.go 的 blank import 加回去,那条测试依然全绿。 于是「已移除」这件事只能靠人记住。 补一条负向断言,在三个互相独立的注册面上各断一次(任一处漏掉都能单独复活 timer): - 工具面:timer_set / timer_list / timer_cancel 不应存在 - 输入面:inputch "timer" 不应存在(定时器注入中断的通道) - 注册表:插件元信息与编译期工厂都不应存在(IsBuiltinPlugin 为假) 已做变异验证:把 timer 插件与 blank import 恢复后,四条断言全部触发、测试 FAIL; 移除后 PASS。故该判据非空转。 (cherry picked from commit d5882ee44a4810fe9e5ee02fb329ad423b065d6e) --- internal/plugins/timer_removed_test.go | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 internal/plugins/timer_removed_test.go diff --git a/internal/plugins/timer_removed_test.go b/internal/plugins/timer_removed_test.go new file mode 100644 index 00000000..c6c3e7cb --- /dev/null +++ b/internal/plugins/timer_removed_test.go @@ -0,0 +1,48 @@ +package plugins + +import ( + "testing" + + "github.com/JianFeeeee/HomeAgent/internal/plugin" +) + +// TestTimerRemovedFromKernel 是一条**负向断言**:timer 已从内核内置插件移出, +// 改由外部 hmap 插件提供。 +// +// 为什么需要它:同包的 TestIntegrationAllPluginsRegister 只断言「该有的工具都在」 +// (正向清单)。正向清单对「多出来」是瞎的 —— 把 internal/plugins/timer 加回 all.go、 +// blank import 一恢复,那条测试依然全绿。于是「移除」这件事无从守护,只能靠人记住。 +// 这条测试把「不该有的不能有」变成机器判据。 +// +// 三个层面各断一次,因为它们的注册路径互相独立、任一处漏掉都能单独复活 timer: +// - 工具(timer_set/list/cancel):用户与 LLM 直接可见的能力面; +// - inputch(timer):定时器到点经它注入 agent,是中断的来源面; +// - 工厂与元信息:plugin 注册表层面,决定 WebUI 插件列表与 IsBuiltinPlugin 判定。 +// +// 注意:本包的测试二进制经 all.go 的 blank import **链入了全部内置插件**, +// 所以这里看到的注册状态就是内核的真实装配结果,不是某个手工构造的假环境。 +func TestTimerRemovedFromKernel(t *testing.T) { + env := setupIntegration(t) + defer env.cleanup() + + // ① 工具面:timer_set / timer_list / timer_cancel 都不应再注册。 + for _, name := range []string{"timer_set", "timer_list", "timer_cancel"} { + if env.stageHost.HasTool(name) { + t.Errorf("工具 %q 仍被内核注册 —— timer 应已从内置插件移出", name) + } + } + + // ② 输入面:inputch "timer" 不应再存在(它是定时器注入中断的通道)。 + if ch, ok := env.iom.LookupInputChannel("timer"); ok { + t.Errorf("inputch %q 仍被注册(Plugin=%q)—— timer 应已从内置插件移出", + ch.Name, ch.Plugin) + } + + // ③ 注册表面:工厂与元信息都不应再有 timer。 + if _, ok := plugin.GetPluginMeta("timer"); ok { + t.Error("插件元信息 \"timer\" 仍被注册 —— timer 应已从内置插件移出") + } + if env.pluginReg.IsBuiltinPlugin("timer") { + t.Error("timer 仍被判定为内置插件(存在编译期工厂)—— 应改由外部 hmap 插件提供") + } +}