Files
HomeAgent/internal/plugin/evtring_close_test.go
JianFeeeee 3f834794c5 refactor: SDK module 路径统一改为 hologramagentsdk(59 文件 + go.mod)
## 为什么必须做

SDK 仓(独立仓库)已把 module 从 `github.com/JianFeeeee/homeagentsdk`
改名为 `hologramagentsdk`。主仓通过 `replace` 直接引用它的**物理目录**:

    replace github.com/JianFeeeee/homeagentsdk => ./third_party/homeagent-sdk

一旦 SDK 侧改成新 module 名,主仓立刻炸:

    go: ./third_party/homeagent-sdk@ used for two different module paths
        (github.com/JianFeeeee/hologramagentsdk and github.com/JianFeeeee/homeagentsdk)

Go **不允许**同一目录被两个 module 路径 replace。所以不能"新旧并存",
只能把主仓 59 个文件的 import 全部改到新名,并删掉旧 replace。

## 一个被证伪的前提

我最初按"third_party/homeagent-sdk 是独立仓库,不能在此仓修改其源码"
来处理,并因此判断两个仓的改动可以隔离。实际上主仓是靠 `replace` 指向
该目录的物理副本 —— **两个仓的改动不可能真正隔离**:SDK 侧改 module 名,
主仓必然跟着改 import。

这个前提应该在做任何改动之前用 `go list -m` 验证,而不是假设。

## 连带修掉两处

| 缺陷 | 性质 |
|---|---|
| `TestLuaSDKMockSingleSource` 失败 | SDK 的 `sdk/lua/sdk.lua` 变了,主仓内嵌副本未同步(跑 `scripts/sync-lua-sdk.sh` 修复) |
| `sdkModuleNames` 分散两处 | 已在 SDK 仓合并为单一数据源(见 SDK 仓 725732b) |

第一条是**副本一致性判据抓到的**,不是我自己发现的 —— 这类判据的价值在此:
两个仓必然有副本,靠人记住"改了 A 要同步 B"是做不到的。

## 验证

- `go build ./...` / `go vet ./...` 干净
- `go test ./... -count=1`:**58 包 0 失败**
- `internal/plugin`(Lua SDK 副本一致性)+ `internal/sdk` 全绿
- 主仓 `third_party/homeagent-sdk/` 与 SDK 仓 `main` 无差异
2026-10-23 15:51:02 +08:00

54 lines
2.0 KiB
Go
Raw 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 plugin
import (
"testing"
"github.com/JianFeeeee/HologramAgent/internal/events"
"github.com/JianFeeeee/HologramAgent/internal/plugin/proc"
pubsdk "github.com/JianFeeeee/hologramagentsdk/sdk"
)
// TestEventRing_CloseUnsubscribesFromBus 钉死:EventRing.Close 必须把
// 自己注册到 Bus 的 handler 全部撤掉。
//
// 为什么关键:那些 handler 会 ring.WritePush —— 也就是**写共享内存**。
// Host.Close 会 munmap 整块区域;若 handler 还挂在 Bus 上,munmap 之后
// 任意一条事件经过 Publish 都会让它写已解除映射的内存 ⇒ SIGSEGV。
// Bus.safeCall 虽有 recover,但 SIGSEGV 是 runtime 致命错误、recover 捕不到,
// 后果是整个 homed 进程被杀。
//
// 判据用「Publish 之后共享内存内容是否被改动」:这是端到端的可观察后果,
// 比断言内部计数器更接近真实危害。
func TestEventRing_CloseUnsubscribesFromBus(t *testing.T) {
host, err := proc.NewHost()
if err != nil {
t.Fatalf("NewHost: %v", err)
}
defer host.Close()
bus := events.NewBus()
er := NewEventRing(host.EvtRing(), int(host.Evtfd().Fd()), bus)
er.EvtRingSubscribeTracked([]pubsdk.EventType{pubsdk.EventSystem})
// 订阅生效:Publish 一条事件应写入事件环。
before := host.EvtRing().Written()
bus.Publish(&events.Event{Type: events.EventSystem, Source: "test", Payload: map[string]interface{}{"a": 1}})
if host.EvtRing().Written() == before {
t.Fatal("订阅后 Publish 未写入事件环(测试前提不成立)")
}
// 关停:退订
er.Close()
// 退订后 Publish 不应再写入事件环(即不再触碰共享内存)。
after := host.EvtRing().Written()
bus.Publish(&events.Event{Type: events.EventSystem, Source: "test", Payload: map[string]interface{}{"b": 2}})
if host.EvtRing().Written() != after {
t.Fatal("EventRing.Close 未从 Bus 退订:\n" +
" munmap 后 handler 仍会写已解除映射的内存 ⇒ SIGSEGV。")
}
// 幂等:重复 Close 不 panic
er.Close()
}