Files
zzet--gortex/cmd/gortex/daemon_controller_worktree_test.go
T
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

121 lines
4.3 KiB
Go

package main
import (
"context"
"encoding/json"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"github.com/zzet/gortex/internal/config"
"github.com/zzet/gortex/internal/graph"
"github.com/zzet/gortex/internal/indexer"
"github.com/zzet/gortex/internal/parser"
"github.com/zzet/gortex/internal/parser/languages"
"github.com/zzet/gortex/internal/search"
)
func wtGit(t *testing.T, dir string, args ...string) {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = dir
cmd.Env = append(os.Environ(),
"GIT_CONFIG_GLOBAL=/dev/null", "GIT_CONFIG_SYSTEM=/dev/null",
"GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@t",
"GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@t")
out, err := cmd.CombinedOutput()
require.NoErrorf(t, err, "git %v: %s", args, out)
}
// buildWorktreeController builds a realController whose MultiIndexer has
// indexed a canonical checkout plus a linked worktree (declaring a
// distinct workspace, with a colliding basename, so both would otherwise
// resolve to the same prefix). Returns the controller, indexer, config
// manager, and the two checkout paths.
func buildWorktreeController(t *testing.T) (*realController, *indexer.MultiIndexer, *config.ConfigManager, string, string) {
t.Helper()
if _, err := exec.LookPath("git"); err != nil {
t.Skip("git binary not available in PATH")
}
canon := filepath.Join(t.TempDir(), "oas-orm")
require.NoError(t, os.MkdirAll(canon, 0o755))
wtGit(t, canon, "init", "-q", "-b", "main")
require.NoError(t, os.WriteFile(filepath.Join(canon, "lib.go"),
[]byte("package lib\n\nfunc C() {}\n"), 0o644))
wtGit(t, canon, "add", ".")
wtGit(t, canon, "commit", "-q", "-m", "init")
wt := filepath.Join(t.TempDir(), "oas-orm")
wtGit(t, canon, "worktree", "add", "-q", "-b", "task", wt)
require.NoError(t, os.WriteFile(filepath.Join(wt, ".gortex.yaml"),
[]byte("workspace: task-ws\n"), 0o644))
require.NoError(t, os.WriteFile(filepath.Join(wt, "feature.go"),
[]byte("package lib\n\nfunc F() {}\n"), 0o644))
cfgPath := filepath.Join(t.TempDir(), "config.yaml")
gc := &config.GlobalConfig{Repos: []config.RepoEntry{{Path: canon}, {Path: wt}}}
gc.SetConfigPath(cfgPath)
require.NoError(t, gc.Save())
cm, err := config.NewConfigManager(cfgPath)
require.NoError(t, err)
g := graph.New()
reg := parser.NewRegistry()
languages.RegisterAll(reg)
mi := indexer.NewMultiIndexer(g, reg, search.NewBM25(), cm, zap.NewNop())
_, err = mi.IndexAll()
require.NoError(t, err)
c := &realController{graph: g, multiIndexer: mi, configManager: cm, logger: zap.NewNop()}
return c, mi, cm, canon, wt
}
func reloadResult(t *testing.T, c *realController) (added, removed int) {
t.Helper()
raw, err := c.Reload(context.Background())
require.NoError(t, err)
var res struct {
Added int `json:"added"`
Removed int `json:"removed"`
}
require.NoError(t, json.Unmarshal(raw, &res))
return res.Added, res.Removed
}
// TestReload_KeepsWorktreeInstance is the regression for the reload
// untrack-diff: a worktree tracked under a derived `<base>@<workspace>`
// prefix must not be untracked on a no-op reload just because its config
// entry's basename matches the canonical's prefix.
func TestReload_KeepsWorktreeInstance(t *testing.T) {
c, mi, _, _, _ := buildWorktreeController(t)
require.NotNil(t, mi.GetMetadata("oas-orm"))
require.NotNil(t, mi.GetMetadata("oas-orm@task-ws"))
added, removed := reloadResult(t, c)
assert.Equal(t, 0, added)
assert.Equal(t, 0, removed, "reload must not untrack the worktree instance")
assert.NotNil(t, mi.GetMetadata("oas-orm@task-ws"), "worktree instance survives reload")
assert.NotNil(t, mi.GetMetadata("oas-orm"), "canonical survives reload")
}
// TestReload_UntracksRemovedWorktree confirms a worktree instance is
// dropped when its entry leaves the config — matched by root path, not a
// recomputed prefix.
func TestReload_UntracksRemovedWorktree(t *testing.T) {
c, mi, cm, _, wt := buildWorktreeController(t)
require.NotNil(t, mi.GetMetadata("oas-orm@task-ws"))
require.NoError(t, cm.Global().RemoveRepo(wt))
require.NoError(t, cm.Global().Save())
_, removed := reloadResult(t, c)
assert.Equal(t, 1, removed)
assert.Nil(t, mi.GetMetadata("oas-orm@task-ws"), "removed worktree is untracked")
assert.NotNil(t, mi.GetMetadata("oas-orm"), "canonical remains tracked")
}