Live apply now accepts only :5433/agent_system_dev plus a data/dev host root, maps stored work dirs fail-closed, and reports unique O_EXCL backups after a parent-directory fsync. Co-authored-by: Cursor <cursoragent@cursor.com>
113 lines
2.9 KiB
Go
113 lines
2.9 KiB
Go
package fsutil
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
func TestWriteFileAtomic_RoundTripAndDirSync(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "output.md")
|
|
if err := WriteFileAtomic(path, []byte("第一版 \n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := WriteFileAtomic(path, []byte("第二版\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != "第二版\n" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestWriteFileAtomic_RenamesThenSyncsParentDir(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "output.md")
|
|
var synced string
|
|
orig := dirSync
|
|
t.Cleanup(func() { dirSync = orig })
|
|
dirSync = func(d string) error {
|
|
synced = d
|
|
return orig(d)
|
|
}
|
|
if err := WriteFileAtomic(path, []byte("durable\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if synced != dir {
|
|
t.Fatalf("parent dir sync got %q want %q", synced, dir)
|
|
}
|
|
}
|
|
|
|
func TestWriteFileAtomic_DirSyncUnsupportedIsIgnored(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "output.md")
|
|
orig := dirSync
|
|
t.Cleanup(func() { dirSync = orig })
|
|
dirSync = func(string) error { return syscall.EINVAL }
|
|
if err := WriteFileAtomic(path, []byte("ok\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, _ := os.ReadFile(path)
|
|
if string(got) != "ok\n" {
|
|
t.Fatalf("got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestWriteFileAtomic_DirSyncHardErrorSurfacesAfterRename(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "output.md")
|
|
orig := dirSync
|
|
t.Cleanup(func() { dirSync = orig })
|
|
dirSync = func(string) error { return errors.New("sync boom") }
|
|
if err := WriteFileAtomic(path, []byte("kept\n"), 0o644); err == nil {
|
|
t.Fatal("hard dir sync error must surface")
|
|
}
|
|
got, err := os.ReadFile(path)
|
|
if err != nil || string(got) != "kept\n" {
|
|
t.Fatalf("rename must have succeeded before sync error: %q %v", got, err)
|
|
}
|
|
}
|
|
|
|
func TestWriteFileAtomicExclusive_RefusesExisting(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "keep.md")
|
|
if err := WriteFileAtomicExclusive(path, []byte("原备份\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := WriteFileAtomicExclusive(path, []byte("覆盖\n"), 0o644); err == nil {
|
|
t.Fatal("exclusive write must refuse existing backup")
|
|
}
|
|
got, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != "原备份\n" {
|
|
t.Fatalf("existing backup mutated: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSyncDir_OpensTarget(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := SyncDir(dir); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := SyncDir(filepath.Join(dir, "missing")); err == nil {
|
|
t.Fatal("missing dir must fail")
|
|
}
|
|
}
|
|
|
|
func TestIgnorableDirSync(t *testing.T) {
|
|
if !ignorableDirSync(syscall.EINVAL) || !ignorableDirSync(syscall.ENOTSUP) || !ignorableDirSync(syscall.ENOSYS) {
|
|
t.Fatal("expected compatibility errno to be ignored")
|
|
}
|
|
if ignorableDirSync(errors.New("other")) {
|
|
t.Fatal("hard errors must not be ignored")
|
|
}
|
|
}
|