mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-11-15 08:51:49 +08:00
## internal/agent/io
原:只有 OutputCapability 位标志 + String
现:
InjectText → 输入事件(source/output_channel/request_id)
InjectInputTo → 显式输出通道被保留
InjectTextSync → 响应回程交到调用方
RegisterDevice → GetDevice → StartAll/StopAll 真实调用设备
重复注册被拒;StartAll 传播设备启动失败
能力标志语义保留(任一位命中)
变异:允许重复注册 / 吞掉启动错误 → 均断言红
## internal/lua
新增:
transform_request 真的执行 Lua body(原来只验证加载与未加载报错)
endpoint/headers 静态声明经公开 API 读回
变异:transform_request 直接返回入参 → 断言红
## internal/system
原:只断言 archived=true 与 baseline 目录非空
现:留档 → 覆盖 → RestoreFileFromBaseline 内容还原为原文
非受保护路径与新建文件不留档
内容未变时重复留档不产生新档案
变异:留档写空内容 / 去掉幂等判断 → 均断言红
## internal/tracker
原:无文件变更时断言无 changeset,rollback 起点为空
现:真实 upper 目录写入 → PostAction 记录 ChangeFileCreated
修改原文 → RollbackLatest 恢复原文内容
新建文件 → RollbackLatest 后消失
空历史定向回滚报错
变异:不记录变更 → 两条断言红
## 验证
go build ./... / go vet ./... PASS
gofmt -l 干净
CI 门禁自检 PASS
go test ./... -count=1 -race 51 测试包 / 100 包无测试 / 0 FAIL
源码目录 _test.go 0
102 lines
3.1 KiB
Go
102 lines
3.1 KiB
Go
package test
|
||
|
||
// internal/tracker 的模块级黑盒判据:真实文件变更 → changeset → 回滚恢复文件。
|
||
// 使用 upper 目录作为可写工作区的真实输入,不碰 t.changeSets 之外无公开替代的状态。
|
||
|
||
import (
|
||
"os"
|
||
"path/filepath"
|
||
"testing"
|
||
|
||
"github.com/JianFeeeee/HologramAgent/internal/tracker"
|
||
)
|
||
|
||
func newTracker(t *testing.T) (*tracker.Tracker, string) {
|
||
t.Helper()
|
||
dir := t.TempDir()
|
||
tr := tracker.NewTracker(filepath.Join(dir, "data"), filepath.Join(dir, "work"))
|
||
if err := tr.Init(); err != nil {
|
||
t.Fatalf("Init: %v", err)
|
||
}
|
||
t.Cleanup(func() { _ = tr.Stop() })
|
||
return tr, filepath.Join(dir, "work", "upper")
|
||
}
|
||
|
||
func writeFile(t *testing.T, path, content string) {
|
||
t.Helper()
|
||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
|
||
func readFile(t *testing.T, path string) string {
|
||
t.Helper()
|
||
b, err := os.ReadFile(path)
|
||
if err != nil {
|
||
t.Fatalf("read %s: %v", path, err)
|
||
}
|
||
return string(b)
|
||
}
|
||
|
||
// TestPostActionRecordsRealFileChange:真实新建文件后 PostAction 必须记录该文件。
|
||
func TestPostActionRecordsRealFileChange(t *testing.T) {
|
||
tr, upper := newTracker(t)
|
||
tr.PreAction("write_file")
|
||
writeFile(t, filepath.Join(upper, "new.txt"), "hello")
|
||
cs := tr.PostAction("write_file")
|
||
if len(cs.Files) != 1 || cs.Files[0].Path != "new.txt" || cs.Files[0].Type != tracker.ChangeFileCreated {
|
||
t.Fatalf("changeset = %+v", cs.Files)
|
||
}
|
||
if !tr.HasChanges() {
|
||
t.Fatal("HasChanges false after a tracked change")
|
||
}
|
||
}
|
||
|
||
// TestRollbackLatestRestoresModifiedContent:修改已存在文件的原文被回滚恢复。
|
||
func TestRollbackLatestRestoresModifiedContent(t *testing.T) {
|
||
tr, upper := newTracker(t)
|
||
const original = "original"
|
||
const changed = "changed"
|
||
writeFile(t, filepath.Join(upper, "cfg.txt"), original)
|
||
|
||
tr.PreAction("edit")
|
||
writeFile(t, filepath.Join(upper, "cfg.txt"), changed)
|
||
tr.PostAction("edit")
|
||
if got := readFile(t, filepath.Join(upper, "cfg.txt")); got != changed {
|
||
t.Fatalf("precondition: %q", got)
|
||
}
|
||
|
||
if err := tr.RollbackLatest(); err != nil {
|
||
t.Fatalf("RollbackLatest: %v", err)
|
||
}
|
||
if got := readFile(t, filepath.Join(upper, "cfg.txt")); got != original {
|
||
t.Fatalf("after rollback = %q, want %q", got, original)
|
||
}
|
||
}
|
||
|
||
// TestRollbackLatestRemovesCreatedFile:新建文件被回滚时应当消失。
|
||
func TestRollbackLatestRemovesCreatedFile(t *testing.T) {
|
||
tr, upper := newTracker(t)
|
||
tr.PreAction("write_file")
|
||
path := filepath.Join(upper, "temp.txt")
|
||
writeFile(t, path, "scratch")
|
||
tr.PostAction("write_file")
|
||
if err := tr.RollbackLatest(); err != nil {
|
||
t.Fatalf("RollbackLatest: %v", err)
|
||
}
|
||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||
t.Fatalf("created file survived rollback (err=%v)", err)
|
||
}
|
||
}
|
||
|
||
// TestRollbackLatestWithoutChangesReportsError:没有变更时定向回滚必须明确报错。
|
||
func TestRollbackLatestWithoutChangesReportsError(t *testing.T) {
|
||
tr, _ := newTracker(t)
|
||
if err := tr.RollbackLatest(); err == nil {
|
||
t.Fatal("RollbackLatest accepted empty history")
|
||
}
|
||
}
|