Files
HomeAgent/internal/tracker/test/tracker_contract_test.go
JianFeeeee b215bfb3ad test: io/lua/system/tracker 改为模块职责级黑盒契约
## 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
2026-11-14 10:22:12 +08:00

102 lines
3.1 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 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")
}
}