Files
Agent-System-Backend/internal/runmgr/rewind_test.go
T
weichen f1302ed5b3 Enable canonical versioned Go module consumption
Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements.

Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate.

Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable.

Refs: Versioned dependencies U1/U3; feature/dependency-workspace
2026-10-13 15:47:16 +00:00

78 lines
2.4 KiB
Go

package runmgr
import (
"os"
"path/filepath"
"testing"
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/tools"
core "git-ssh.u1680832.nyat.app/weichen/Agent-System-Core.git"
)
func TestRewindRestoresTrackedWriteAndLeavesShellFile(t *testing.T) {
c, st := newExecEnv(t)
root := t.TempDir()
c.mgr.SetWorkspaceRoot(root)
c.eff = core.EffectiveSettings{"runtime": map[string]any{"fsTools": true}}
if err := tools.RegisterFSTools(c.mgr.registry); err != nil {
t.Fatal(err)
}
msg := core.Message{ConversationID: c.run.ConversationID, Role: core.RoleUser, Parts: []core.Part{{Type: core.PartText, Text: "go"}}}
if err := st.AppendMessage(&msg); err != nil {
t.Fatal(err)
}
c.userMessage = msg
res := c.ExecuteTool(core.ToolCallRequest{
CallID: "w1", Name: "fs_write_file",
Arguments: []byte(`{"path":"note.txt","content":"new"}`),
})
if res.Status != "ok" {
t.Fatalf("write %s %s", res.Status, res.Output)
}
sandbox := c.ConversationSandbox()
if err := os.WriteFile(filepath.Join(sandbox, "shell.txt"), []byte("from-shell"), 0o644); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(sandbox, "note.txt"), []byte("external"), 0o644); err != nil {
t.Fatal(err)
}
// 外部改动应被跳过。再写一个只被追踪、没有被外改的文件。
res = c.ExecuteTool(core.ToolCallRequest{
CallID: "w2", Name: "fs_write_file",
Arguments: []byte(`{"path":"kept.txt","content":"yes"}`),
})
if res.Status != "ok" {
t.Fatalf("kept %s %s", res.Status, res.Output)
}
got, err := c.mgr.RewindFiles(c.run.Owner, c.run.ConversationID, msg.ID)
if err != nil {
t.Fatal(err)
}
if len(got.Restored) != 1 || got.Restored[0] != "kept.txt" {
t.Fatalf("restored %#v skipped %#v", got.Restored, got.Skipped)
}
if len(got.Skipped) != 1 || got.Skipped[0] != "note.txt" {
t.Fatalf("skipped %#v", got.Skipped)
}
if _, err := os.Stat(filepath.Join(sandbox, "kept.txt")); !os.IsNotExist(err) {
t.Fatal("tracked create was not removed")
}
side, err := os.ReadFile(filepath.Join(sandbox, "shell.txt"))
if err != nil || string(side) != "from-shell" {
t.Fatalf("shell file %q %v", side, err)
}
msgs, err := st.ListMessages(c.run.ConversationID)
if err != nil {
t.Fatal(err)
}
var note string
for _, m := range msgs {
if m.Role == core.RoleSystem && len(m.Parts) > 0 {
note = m.Parts[0].Text
}
}
if note == "" {
t.Fatal("missing system note")
}
}