Files
homeagent-sdk/example/commondev/rawfile_presence_test.go
JianFeeeee 330c0c9246 test(commondev): 守住 rawfile/ 不进库却决定包能否运行的隐患
## 背景

`example/commondev/rawfile/.gitignore` 写着 `*`:rawfile 里是随包资源
(可能是上百兆 node/pi 二进制),进版本库会让克隆变慢、每次升级产生
巨型 diff。**这是设计意图**,不是疏忽。

但代价很具体:

	本地打包  → 包里 571 个 runtime 条目(工作区已备好资源)→ 冒烟通过
	CI  打包  → 包里 0 个 runtime 条目(干净克隆没有资源)  → 插件起不来

而两次构建的**日志都写着"成功"**。这类"本地绿、别处坏"我们吃过一次:
TestHmapdevTemplateImplementsAllPluginMgrMethods 读了 gitignore 的文件,
本地绿、CI 红。

本次尤其危险:interrupt 的实现**同时**落在 sidecar.mjs(已进库)和
rawfile/runtime/*/sidecar.mjs(未进库)两处。只改前者,判据全绿、
包里的 sidecar 却还是旧的 —— 取消能力在发布版里根本不存在。

## 判据做什么

不能要求 rawfile/ 必须有内容(干净克隆本来就没有)。但可以:

 · 有内容时,每个 CLI 目录必须有 sidecar.mjs 或 driver.json
 · pi/zcode 的 sidecar **必须**支持 interrupt
 · 没有内容时,用 t.Logf **大声说明**"此状态下打出的包不含 sidecar",
   让这件事出现在测试输出里,而不是静默

## 变异

删掉 rawfile/runtime/pi/sidecar.mjs 的 interrupt case →
判据报"打包后 commondev_agent_interrupt 会失效(源码改了但资源没同步)"
2026-10-18 10:18:40 +08:00

79 lines
3.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 main
// rawfile/ 内容**不进版本库**,却决定发布包能不能跑。
//
// ## 为什么需要这条判据
//
// `example/commondev/rawfile/.gitignore` 写着 `*`(只放行 .gitignore/.gitkeep):
// 资源可能是上百兆的 node/pi 二进制,进版本库会让克隆变慢、每次升级产生
// 巨型 diff。这是设计意图,不是疏忽。
//
// 但代价是:**CI 从零克隆时 rawfile/ 是空的**。于是
//
// 本地打包 → 包里 571 个 runtime 条目(工作区里已备好)→ 冒烟通过
// CI 打包 → 包里 0 个 runtime 条目 → 发布出去的插件起不来
//
// 而两次构建的**日志都写着"成功"**。这类"本地绿、CI 红/坏"我们已经
// 吃过一次(TestHmapdevTemplateImplementsAllPluginMgrMethods 读 gitignore
// 的文件,本地绿 CI 红)。
//
// ## 判据的作用
//
// 不能要求 rawfile/ 必须有内容(干净克隆本来就没有),但可以:
// · 有内容时,必须包含我们自己的 sidecar(而不是只有 node_modules)
// · 没有内容时,明确说明"这个构建产不出可用包" —— 让人看见,而不是静默
import (
"os"
"path/filepath"
"strings"
"testing"
)
// ★★★ sidecar 是插件运行时的必需件,不能只靠"本地恰好有"。
func TestRuntimeSidecarsPresentOrLoudlyAbsent(t *testing.T) {
root := filepath.Join("rawfile", "runtime")
ents, err := os.ReadDir(root)
if err != nil {
// 干净克隆:rawfile/runtime 根本不存在。
// 这不是测试失败,但必须**大声说出来** —— 因为此时打出的包不可用。
t.Logf("★★ 注意:%s 不存在(干净克隆的正常状态)。"+
"此状态下 build-examples.sh 打出的 commondev.hmap **不含 sidecar**,"+
"插件在该包里无法投递任务。发布前必须在有 rawfile 资源的工作区打包。", root)
return
}
var clis []string
for _, e := range ents {
if e.IsDir() {
clis = append(clis, e.Name())
}
}
if len(clis) == 0 {
t.Logf("★★ 注意:%s 存在但没有 CLI 子目录 —— 同上,包不可用。", root)
return
}
// 有内容时,每个 CLI 都必须有 sidecar.mjs(或缺省的 driver 脚本)
for _, cli := range clis {
sc := filepath.Join(root, cli, "sidecar.mjs")
b, err := os.ReadFile(sc)
if err != nil {
// driver.json 可以指定别的脚本名
dj := filepath.Join(root, cli, "driver.json")
if _, derr := os.Stat(dj); derr == nil {
continue // 由 driver.json 指定,正常
}
t.Fatalf("★ %s 有目录但没有 sidecar.mjs 也没有 driver.json —— "+
"该 CLI 无法运行", cli)
}
// pi/zcode 的 sidecar 必须支持 interrupt(否则取消能力在包里失效)
if cli == "pi" || cli == "zcode" {
if !strings.Contains(string(b), `case "interrupt":`) {
t.Fatalf("★ %s/sidecar.mjs 没有 interrupt —— "+
"打包后 commondev_agent_interrupt 会失效(源码改了但资源没同步)", cli)
}
}
}
t.Logf("rawfile/runtime 下 %d 个 CLI 的 sidecar 齐备: %v", len(clis), clis)
}