Files
wehub-resource-sync f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:36 +08:00

180 lines
6.1 KiB
Go

package remotesync
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMirrorDirDisambiguatesSanitizedCollisions(t *testing.T) {
a := MirrorDir("/data", "host:8080")
b := MirrorDir("/data", "host_8080")
assert.NotEqual(t, a, b)
assert.True(t, strings.HasPrefix(a, filepath.Join("/data", "remote-mirrors")+string(filepath.Separator)))
assert.NotContains(t, filepath.Base(a), ":")
}
func writeMirrorFile(t *testing.T, root, remotePath, content string, mtime time.Time) string {
t.Helper()
local, err := safeRemappedRemotePath(root, remotePath)
require.NoError(t, err)
require.NoError(t, os.MkdirAll(filepath.Dir(local), 0o755))
require.NoError(t, os.WriteFile(local, []byte(content), 0o644))
require.NoError(t, os.Chtimes(local, mtime, mtime))
return local
}
func TestMirrorDiffFetchesNewChangedAndDeletesStale(t *testing.T) {
root := t.TempDir()
base := time.Date(2026, 7, 8, 10, 0, 0, 111222333, time.UTC)
unchanged := "/home/u/.claude/projects/p/unchanged.jsonl"
changedMtime := "/home/u/.claude/projects/p/newer.jsonl"
changedSize := "/home/u/.claude/projects/p/grew.jsonl"
writeMirrorFile(t, root, unchanged, "aa", base)
writeMirrorFile(t, root, changedMtime, "bb", base)
writeMirrorFile(t, root, changedSize, "cc", base)
staleLocal := writeMirrorFile(t, root, "/home/u/.claude/projects/p/stale.jsonl", "dd", base)
m := Manifest{Files: []ManifestEntry{
{Path: unchanged, Size: 2, MtimeNS: base.UnixNano()},
{Path: changedMtime, Size: 2, MtimeNS: base.Add(3 * time.Second).UnixNano()},
{Path: changedSize, Size: 9, MtimeNS: base.UnixNano()},
{Path: "/home/u/.claude/projects/p/new.jsonl", Size: 1, MtimeNS: base.UnixNano()},
}}
delta, err := MirrorDiff(root, m)
require.NoError(t, err)
assert.Equal(t, []string{
changedSize,
"/home/u/.claude/projects/p/new.jsonl",
changedMtime,
}, delta.Fetch)
assert.Equal(t, []string{staleLocal}, delta.Deletions)
assert.Equal(t, 4, delta.Total)
}
func TestMirrorDiffTruncatesMtimeToMicroseconds(t *testing.T) {
root := t.TempDir()
base := time.Date(2026, 7, 8, 10, 0, 0, 111222000, time.UTC)
path := "/home/u/.claude/projects/p/s.jsonl"
writeMirrorFile(t, root, path, "aa", base)
m := Manifest{Files: []ManifestEntry{
// Same microsecond, different nanosecond remainder: unchanged.
{Path: path, Size: 2, MtimeNS: base.UnixNano() + 999},
}}
delta, err := MirrorDiff(root, m)
require.NoError(t, err)
assert.Empty(t, delta.Fetch)
assert.Empty(t, delta.Deletions)
}
func TestMirrorDiffEmptyMirrorFetchesEverything(t *testing.T) {
root := filepath.Join(t.TempDir(), "missing")
m := Manifest{Files: []ManifestEntry{
{Path: "/home/u/.claude/projects/p/s.jsonl", Size: 1, MtimeNS: 1},
}}
delta, err := MirrorDiff(root, m)
require.NoError(t, err)
assert.Len(t, delta.Fetch, 1)
assert.Empty(t, delta.Deletions)
}
func TestApplyMirrorDeletionsConfinedToRoot(t *testing.T) {
root := t.TempDir()
outside := filepath.Join(t.TempDir(), "victim.txt")
require.NoError(t, os.WriteFile(outside, []byte("x"), 0o644))
err := ApplyMirrorDeletions(root, []string{outside})
require.Error(t, err)
assert.FileExists(t, outside)
inside := writeMirrorFile(t, root, "/home/u/.claude/projects/p/s.jsonl", "x",
time.Date(2026, 7, 8, 10, 0, 0, 0, time.UTC))
require.NoError(t, ApplyMirrorDeletions(root, []string{inside}))
assert.NoFileExists(t, inside)
}
func TestApplyMirrorDeletionsPrunesEmptyDirs(t *testing.T) {
root := t.TempDir()
mtime := time.Date(2026, 7, 8, 10, 0, 0, 0, time.UTC)
inside := writeMirrorFile(t,
root, "/home/u/.claude/projects/p/nested/s.jsonl", "x", mtime)
sibling := writeMirrorFile(t,
root, "/home/u/.claude/projects/other.jsonl", "y", mtime)
require.NoError(t, ApplyMirrorDeletions(root, []string{inside}))
assert.NoDirExists(t, filepath.Dir(inside))
assert.NoDirExists(t, filepath.Dir(filepath.Dir(inside)))
assert.FileExists(t, sibling)
assert.DirExists(t, filepath.Dir(sibling))
}
func TestAcquireMirrorLockIsExclusive(t *testing.T) {
root := filepath.Join(t.TempDir(), "mirror")
lock, err := AcquireMirrorLock(context.Background(), root)
require.NoError(t, err)
t.Cleanup(func() { _ = lock.Close() })
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
_, err = AcquireMirrorLock(ctx, root)
require.Error(t, err)
require.NoError(t, lock.Close())
second, err := AcquireMirrorLock(context.Background(), root)
require.NoError(t, err)
require.NoError(t, second.Close())
}
func TestAcquireMirrorLockCanonicalizesSymlinkedParent(t *testing.T) {
base := t.TempDir()
realParent := filepath.Join(base, "real")
require.NoError(t, os.MkdirAll(realParent, 0o755))
linkParent := filepath.Join(base, "link")
if err := os.Symlink(realParent, linkParent); err != nil {
t.Skipf("symlinks unavailable: %v", err)
}
realRoot := filepath.Join(realParent, "data", "remote-mirrors", "shared")
aliasRoot := filepath.Join(linkParent, "data", "remote-mirrors", "shared")
lock, err := AcquireMirrorLock(context.Background(), realRoot)
require.NoError(t, err)
t.Cleanup(func() { _ = lock.Close() })
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
aliasLock, err := AcquireMirrorLock(ctx, aliasRoot)
cancel()
if aliasLock != nil {
require.NoError(t, aliasLock.Close())
}
assert.Error(t, err, "symlink aliases must contend on one canonical lock")
require.NoError(t, lock.Close())
aliasLock, err = AcquireMirrorLock(context.Background(), aliasRoot)
require.NoError(t, err)
require.NoError(t, aliasLock.Close())
}
func TestRemoveMirrorTypeConflictsRemovesDirAtFetchPath(t *testing.T) {
root := t.TempDir()
wedged := "/archives/claude/projects/p/s.jsonl"
local, err := safeRemappedRemotePath(root, wedged)
require.NoError(t, err)
require.NoError(t, os.MkdirAll(local, 0o755))
kept := writeMirrorFile(t, root, "/home/u/.claude/projects/p/other.jsonl",
"x", time.Date(2026, 7, 8, 10, 0, 0, 0, time.UTC))
require.NoError(t, RemoveMirrorTypeConflicts(root, []string{
wedged,
"/home/u/.claude/projects/p/other.jsonl",
"/home/u/.claude/projects/p/absent.jsonl",
}))
assert.NoDirExists(t, local)
assert.FileExists(t, kept)
}