Files
HomeAgent/internal/plugins/skillmgr/test/descriptions_contract_test.go
JianFeeeee e74d66492d test: 按模块导出接口重写黑盒判据(批次 13:sdk / skillmgr / remotedevice)
三个模块新增 test/ 黑盒契约,测试仅使用模块导出 API。

## internal/sdk

    EffectiveProxyAuthNormalizesLegacyAndEmpty
    ProxyHostNormalizationAndValidation
    NewConfigGetPutRoundTrip
    BuiltinProxyRegistrySnapshotsAndClear

覆盖鉴权归一化、DNS host 标签校验、ConfigAPI 往返、内置反代声明表快照与清理。

## internal/plugins/skillmgr

    SkillDescriptionsListsScannedSkillsInStableOrder
    SkillDescriptionsEmptyBeforeStart

通过公开 New/Start/SkillDescriptions/Name 验证技能目录扫描、稳定排序与空目录行为。

## internal/plugins/remotedevice

    SaveResultThenGetResult
    SupportsToolForUnknownAndUnknownCapability
    SaveInlineMediaRequiresDirectoryAndPersistsBytes

覆盖结果存取、未知设备能力查询、媒体目录配置、base64 落盘、摘要和元数据。

## 变异验证

    sdk       注册版本不递增                 → registration did not advance public version
    skillmgr  不写入技能表                   → scanned descriptions missing
    remotedevice 丢弃 SaveResult             → GetResult=false

## 验证

    go build ./...                            PASS
    go vet ./...                              PASS
    gofmt -l                                  干净
    python3 .github/scripts/check-ci-gates.py PASS
    go test ./... -count=1                    48 个测试包 / 100 包无测试 / 0 FAIL
    3 个新包 -race                            全绿
    源码目录 _test.go                         0
2026-11-09 21:13:49 +08:00

55 lines
1.8 KiB
Go

package test
// skillmgr 黑盒判据:技能目录输入 → SkillDescriptions 可观察文本。
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/JianFeeeee/HologramAgent/internal/plugins/skillmgr"
sdkpkg "github.com/JianFeeeee/HologramAgent/internal/sdk"
)
func TestSkillDescriptionsListsScannedSkillsInStableOrder(t *testing.T) {
dir := t.TempDir()
for name, desc := range map[string]string{"zeta": "处理 zeta 的工作流。", "alpha": "处理 alpha 的工作流。"} {
p := filepath.Join(dir, name)
if err := os.MkdirAll(p, 0o755); err != nil {
t.Fatal(err)
}
body := "# " + name + "\n\n" + desc + "\n"
if err := os.WriteFile(filepath.Join(p, "SKILL.md"), []byte(body), 0o644); err != nil {
t.Fatal(err)
}
}
p := skillmgr.New("contract-skillmgr", dir)
// Start performs the public directory scan; provide only the two public
// registrar callbacks required by the plugin SDK and no hidden test hooks.
sdk := sdkpkg.New("contract-skillmgr", sdkpkg.SDKConfig{
RegTool: func(string, sdkpkg.ToolDef, sdkpkg.ToolHandler) error { return nil },
})
if err := p.Start(sdk); err != nil {
t.Fatalf("Start: %v", err)
}
t.Cleanup(func() { _ = p.Stop() })
got := p.SkillDescriptions()
if !strings.Contains(got, "alpha: 处理 alpha 的工作流。") || !strings.Contains(got, "zeta: 处理 zeta 的工作流。") {
t.Fatalf("scanned descriptions missing: %q", got)
}
if strings.Index(got, "alpha:") > strings.Index(got, "zeta:") {
t.Fatalf("descriptions not in stable name order: %q", got)
}
if p.Name() != "contract-skillmgr" {
t.Fatalf("Name=%q", p.Name())
}
}
func TestSkillDescriptionsEmptyBeforeStart(t *testing.T) {
p := skillmgr.New("empty", t.TempDir())
if got := p.SkillDescriptions(); got != "" {
t.Fatalf("unexpected descriptions: %q", got)
}
}