Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions internal/gitvolume/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,26 @@ func TestNewWorkspace_NoConfig(t *testing.T) {
assert.Error(t, ctx.Load("", true))
}

func TestNewWorkspace_EmptyConfig(t *testing.T) {
repoDir, cleanup := setupTestGitRepo(t)
defer cleanup()

configPath := filepath.Join(repoDir, ConfigFileName)
require.NoError(t, os.WriteFile(configPath, []byte(""), 0644))

// Change to repo dir
oldDir, err := os.Getwd()
require.NoError(t, err)
defer func() { _ = os.Chdir(oldDir) }()
require.NoError(t, os.Chdir(repoDir))

ctx, err := NewContext()
require.NoError(t, err)
// Should not error, just empty volumes
require.NoError(t, ctx.Load("", true))
assert.Equal(t, 0, len(ctx.Volumes))
}

func TestNewWorkspace_RelativeCustomPath(t *testing.T) {
repoDir, cleanup := setupTestGitRepo(t)
defer cleanup()
Expand Down Expand Up @@ -392,3 +412,99 @@ func TestHasGlobalVolumes(t *testing.T) {
})
}
}

func TestCheckStatus(t *testing.T) {
sourceDir, targetDir, cleanup := setupTestEnv(t)
defer cleanup()

t.Run("Link OK", func(t *testing.T) {
vol := Volume{Source: "source1.txt", Target: "link.txt", Mode: ModeLink}
vol.SourcePath = filepath.Join(sourceDir, "source1.txt")
vol.TargetPath = filepath.Join(targetDir, "link.txt")
require.NoError(t, os.Symlink(vol.SourcePath, vol.TargetPath))
defer os.Remove(vol.TargetPath)
status := vol.CheckStatus()
assert.Equal(t, StatusOKLinked, status.Status)
})

t.Run("Link WrongLink", func(t *testing.T) {
vol := Volume{Source: "source1.txt", Target: "wrong_link.txt", Mode: ModeLink}
vol.SourcePath = filepath.Join(sourceDir, "source1.txt")
vol.TargetPath = filepath.Join(targetDir, "wrong_link.txt")
require.NoError(t, os.Symlink(filepath.Join(sourceDir, "source2.txt"), vol.TargetPath))
defer os.Remove(vol.TargetPath)
status := vol.CheckStatus()
assert.Equal(t, StatusWrongLink, status.Status)
})

t.Run("Link ExistsNotLink", func(t *testing.T) {
vol := Volume{Source: "source1.txt", Target: "notlink.txt", Mode: ModeLink}
vol.SourcePath = filepath.Join(sourceDir, "source1.txt")
vol.TargetPath = filepath.Join(targetDir, "notlink.txt")
require.NoError(t, os.WriteFile(vol.TargetPath, []byte("file"), 0644))
defer os.Remove(vol.TargetPath)
status := vol.CheckStatus()
assert.Equal(t, StatusExistsNotLink, status.Status)
})

t.Run("Copy OK", func(t *testing.T) {
vol := Volume{Source: "source1.txt", Target: "copy_ok.txt", Mode: ModeCopy}
vol.SourcePath = filepath.Join(sourceDir, "source1.txt")
vol.TargetPath = filepath.Join(targetDir, "copy_ok.txt")
require.NoError(t, copyFile(vol.SourcePath, vol.TargetPath))
defer os.Remove(vol.TargetPath)
status := vol.CheckStatus()
assert.Equal(t, StatusOKCopied, status.Status)
})

t.Run("Copy Modified", func(t *testing.T) {
vol := Volume{Source: "source1.txt", Target: "copy_mod.txt", Mode: ModeCopy}
vol.SourcePath = filepath.Join(sourceDir, "source1.txt")
vol.TargetPath = filepath.Join(targetDir, "copy_mod.txt")
require.NoError(t, os.WriteFile(vol.TargetPath, []byte("modified"), 0644))
defer os.Remove(vol.TargetPath)
status := vol.CheckStatus()
assert.Equal(t, StatusModified, status.Status)
})

t.Run("MissingSource", func(t *testing.T) {
vol := Volume{Source: "missing.txt", Target: "x.txt", Mode: ModeLink}
vol.SourcePath = filepath.Join(sourceDir, "missing.txt")
vol.TargetPath = filepath.Join(targetDir, "x.txt")
status := vol.CheckStatus()
assert.Equal(t, StatusMissingSource, status.Status)
})

t.Run("NotMounted", func(t *testing.T) {
vol := Volume{Source: "source1.txt", Target: "nomount.txt", Mode: ModeLink}
vol.SourcePath = filepath.Join(sourceDir, "source1.txt")
vol.TargetPath = filepath.Join(targetDir, "nomount.txt")
status := vol.CheckStatus()
assert.Equal(t, StatusNotMounted, status.Status)
})

t.Run("Copy Dir OK", func(t *testing.T) {
configDir := filepath.Join(sourceDir, "statusdir")
require.NoError(t, os.Mkdir(configDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(configDir, "f.txt"), []byte("data"), 0644))
vol := Volume{Source: "statusdir", Target: "statusdir", Mode: ModeCopy}
vol.SourcePath = configDir
vol.TargetPath = filepath.Join(targetDir, "statusdir")
require.NoError(t, copyDir(vol.SourcePath, vol.TargetPath))
status := vol.CheckStatus()
assert.Equal(t, StatusOKCopied, status.Status)
})

t.Run("Copy Dir Modified", func(t *testing.T) {
configDir := filepath.Join(sourceDir, "statusdir2")
require.NoError(t, os.Mkdir(configDir, 0755))
require.NoError(t, os.WriteFile(filepath.Join(configDir, "f.txt"), []byte("data"), 0644))
vol := Volume{Source: "statusdir2", Target: "statusdir2", Mode: ModeCopy}
vol.SourcePath = configDir
vol.TargetPath = filepath.Join(targetDir, "statusdir2")
require.NoError(t, copyDir(vol.SourcePath, vol.TargetPath))
require.NoError(t, os.WriteFile(filepath.Join(vol.TargetPath, "f.txt"), []byte("changed"), 0644))
status := vol.CheckStatus()
assert.Equal(t, StatusModified, status.Status)
})
}
132 changes: 132 additions & 0 deletions internal/gitvolume/debug_find_common_dir_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package gitvolume

import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestDebugFindCommonDir(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "git-volume-debug-*")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)

// 1. Regular Repository
t.Run("Regular Repository", func(t *testing.T) {
repoDir := filepath.Join(tmpDir, "regular")
require.NoError(t, os.MkdirAll(repoDir, 0755))

cmd := exec.Command("git", "init", repoDir)
require.NoError(t, cmd.Run())

// Set identity
cmd = exec.Command("git", "-C", repoDir, "config", "user.email", "test@test.com")
require.NoError(t, cmd.Run())
cmd = exec.Command("git", "-C", repoDir, "config", "user.name", "Test")
require.NoError(t, cmd.Run())

// Create a commit so we can create a worktree
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("init"), 0644))
cmd = exec.Command("git", "-C", repoDir, "add", ".")
require.NoError(t, cmd.Run())
cmd = exec.Command("git", "-C", repoDir, "commit", "-m", "Initial commit")
require.NoError(t, cmd.Run())

commonDir, err := findCommonDir(repoDir)
require.NoError(t, err)

realRepoDir, _ := filepath.EvalSymlinks(repoDir)
assert.Equal(t, realRepoDir, commonDir, "Common dir of regular repo root should be itself")

// Worktree from Regular Repo
wtDir := filepath.Join(tmpDir, "regular-worktree")
cmd = exec.Command("git", "-C", repoDir, "worktree", "add", wtDir)
require.NoError(t, cmd.Run())

commonDirWT, err := findCommonDir(wtDir)
require.NoError(t, err)

commonDirWT, err = filepath.EvalSymlinks(commonDirWT)
require.NoError(t, err)

assert.Equal(t, realRepoDir, commonDirWT, "Worktree from regular repo should point back to main repo root")
})

// 2. Bare Repository
t.Run("Bare Repository", func(t *testing.T) {
bareRepoDir := filepath.Join(tmpDir, "bare.git")
cmd := exec.Command("git", "init", "--bare", bareRepoDir)
require.NoError(t, cmd.Run())

realBareDir, err := filepath.EvalSymlinks(bareRepoDir)
require.NoError(t, err)

commonDir, err := findCommonDir(bareRepoDir)
require.NoError(t, err)

commonDir, err = filepath.EvalSymlinks(commonDir)
require.NoError(t, err)

assert.Equal(t, realBareDir, commonDir, "Common dir of bare repo root should be itself")

// Create a worktree from bare repo
// Need a commit first? Bare repos don't have commits unless pushed or created from existing.
// Let's create a regular repo first, then clone as bare to have commits.
srcRepo := filepath.Join(tmpDir, "src")
require.NoError(t, os.MkdirAll(srcRepo, 0755))
cmd = exec.Command("git", "init", srcRepo)
require.NoError(t, cmd.Run())

cmd = exec.Command("git", "-C", srcRepo, "config", "user.email", "test@test.com")
require.NoError(t, cmd.Run())
cmd = exec.Command("git", "-C", srcRepo, "config", "user.name", "Test")
require.NoError(t, cmd.Run())

require.NoError(t, os.WriteFile(filepath.Join(srcRepo, "README.md"), []byte("init"), 0644))
cmd = exec.Command("git", "-C", srcRepo, "add", ".")
require.NoError(t, cmd.Run())
cmd = exec.Command("git", "-C", srcRepo, "commit", "-m", "Initial commit")
require.NoError(t, cmd.Run())

// Clone as bare
bareCloned := filepath.Join(tmpDir, "bare-cloned.git")
cmd = exec.Command("git", "clone", "--bare", srcRepo, bareCloned)
require.NoError(t, cmd.Run())

realBareCloned, err := filepath.EvalSymlinks(bareCloned)
require.NoError(t, err)

// Create worktree
wtDir := filepath.Join(tmpDir, "bare-worktree")
cmd = exec.Command("git", "-C", bareCloned, "worktree", "add", wtDir)
if out, err := cmd.CombinedOutput(); err != nil {
t.Logf("Git output: %s", string(out))
require.NoError(t, err)
}

commonDirWT, err := findCommonDir(wtDir)
require.NoError(t, err)
commonDirWT, err = filepath.EvalSymlinks(commonDirWT)
require.NoError(t, err)

// DEBUGGING: Check what git rev-parse --git-common-dir returns here
cmd = exec.Command("git", "-C", wtDir, "rev-parse", "--git-common-dir")
out, err := cmd.Output()
if err != nil {
t.Logf("git rev-parse --git-common-dir failed: %v", err)
}
gitCommonDir := strings.TrimSpace(string(out))
t.Logf("git rev-parse --git-common-dir in worktree: %s", gitCommonDir)

// Check isBareRepository on that dir
isBare, err := isBareRepository(gitCommonDir)
t.Logf("isBareRepository(%s) = %v, err=%v", gitCommonDir, isBare, err)

assert.Equal(t, realBareCloned, commonDirWT, "Worktree from bare repo should point back to bare repo root")
})
}
Loading