Files
kandev/apps/backend/internal/agentctl/server/process/manager_submodule_test.go
T
2026-08-06 15:04:19 +01:00

145 lines
5.1 KiB
Go

package process
import (
"context"
"os"
"path/filepath"
"slices"
"strings"
"testing"
"github.com/kandev/kandev/internal/agentctl/server/config"
)
func TestManager_DiscoversNestedSubmoduleScopesWithStableAnchors(t *testing.T) {
parent, parentCleanup := setupTestRepo(t)
t.Cleanup(parentCleanup)
direct, directCleanup := setupTestRepo(t)
t.Cleanup(directCleanup)
nested, nestedCleanup := setupTestRepo(t)
t.Cleanup(nestedCleanup)
runGit(t, direct, "-c", "protocol.file.allow=always", "submodule", "add", nested, "vendor/inner")
runGit(t, direct, "add", ".")
runGit(t, direct, "commit", "-m", "add nested submodule")
runGit(t, parent, "-c", "protocol.file.allow=always", "submodule", "add", direct, "vendor/outer")
runGit(t, parent, "-c", "protocol.file.allow=always", "submodule", "update", "--init", "--recursive")
runGit(t, parent, "add", ".")
runGit(t, parent, "commit", "-m", "add direct submodule")
runGit(t, parent, "push", "origin", "main")
runGit(t, parent, "checkout", "-b", "feature/review")
directAnchor := strings.TrimSpace(runGit(t, parent, "rev-parse", "origin/main:vendor/outer"))
nestedAnchor := strings.TrimSpace(runGit(t, filepath.Join(parent, "vendor/outer"), "rev-parse", "HEAD:vendor/inner"))
mgr := NewManager(&config.InstanceConfig{
WorkDir: parent,
BaseBranches: map[string]string{"": "main"},
}, newTestLogger(t))
t.Cleanup(mgr.stopWorkspaceTrackers)
if mgr.GetWorkspaceTracker().RepositoryName() != "" {
t.Fatalf("root tracker RepositoryName() = %q, want empty root scope", mgr.GetWorkspaceTracker().RepositoryName())
}
if got := mgr.RepoSubpaths(); !slices.Equal(got, []string{"vendor/outer", "vendor/outer/vendor/inner"}) {
t.Fatalf("RepoSubpaths() = %v, want nested scopes", got)
}
if got := mgr.RepositoryScopes(); !slices.Equal(got, []string{"", "vendor/outer", "vendor/outer/vendor/inner"}) {
t.Fatalf("RepositoryScopes() = %v, want root and nested scopes", got)
}
directTracker, err := mgr.GetWorkspaceTrackerFor("vendor/outer")
if err != nil {
t.Fatalf("direct tracker: %v", err)
}
if got := directTracker.BaseBranch(); got != directAnchor {
t.Errorf("direct BaseBranch() = %q, want parent gitlink %q", got, directAnchor)
}
nestedTracker, err := mgr.GetWorkspaceTrackerFor("vendor/outer/vendor/inner")
if err != nil {
t.Fatalf("nested tracker: %v", err)
}
if got := nestedTracker.BaseBranch(); got != nestedAnchor {
t.Errorf("nested BaseBranch() = %q, want parent gitlink %q", got, nestedAnchor)
}
if _, err := mgr.GetWorkspaceTrackerFor("vendor/outer"); err != nil {
t.Fatalf("repeated direct tracker lookup: %v", err)
}
}
func TestManager_RescanDiscoversNewNestedSubmoduleAndRetainsRoot(t *testing.T) {
parent, parentCleanup := setupTestRepo(t)
t.Cleanup(parentCleanup)
child, childCleanup := setupTestRepo(t)
t.Cleanup(childCleanup)
mgr := NewManager(&config.InstanceConfig{WorkDir: parent}, newTestLogger(t))
t.Cleanup(mgr.stopWorkspaceTrackers)
root := mgr.GetWorkspaceTracker()
if got := mgr.RepoSubpaths(); len(got) != 0 {
t.Fatalf("initial RepoSubpaths() = %v, want none", got)
}
runGit(t, parent, "-c", "protocol.file.allow=always", "submodule", "add", child, "vendor/lib")
runGit(t, parent, "add", ".")
runGit(t, parent, "commit", "-m", "add submodule")
if err := mgr.RescanRepositories(context.Background(), parent); err != nil {
t.Fatalf("rescan: %v", err)
}
if mgr.GetWorkspaceTracker() != root {
t.Fatal("rescan replaced the root tracker for an unchanged workspace")
}
if got := mgr.RepoSubpaths(); !slices.Equal(got, []string{"vendor/lib"}) {
t.Fatalf("rescanned RepoSubpaths() = %v, want vendor/lib", got)
}
if tracker, err := mgr.GetWorkspaceTrackerFor("vendor/lib"); err != nil || tracker == nil {
t.Fatalf("rescanned child tracker = %v, err %v", tracker, err)
}
}
func TestManager_SkipsUninitializedSubmoduleWithoutLosingRoot(t *testing.T) {
parent, parentCleanup := setupTestRepo(t)
t.Cleanup(parentCleanup)
child, childCleanup := setupTestRepo(t)
t.Cleanup(childCleanup)
runGit(t, parent, "-c", "protocol.file.allow=always", "submodule", "add", child, "vendor/lib")
runGit(t, parent, "add", ".")
runGit(t, parent, "commit", "-m", "add submodule")
if err := os.RemoveAll(filepath.Join(parent, "vendor/lib")); err != nil {
t.Fatalf("remove submodule worktree: %v", err)
}
mgr := NewManager(&config.InstanceConfig{WorkDir: parent}, newTestLogger(t))
t.Cleanup(mgr.stopWorkspaceTrackers)
if got := mgr.RepoSubpaths(); len(got) != 0 {
t.Fatalf("uninitialized RepoSubpaths() = %v, want none", got)
}
if mgr.GetWorkspaceTracker() == nil {
t.Fatal("root tracker was lost when submodule was unavailable")
}
}
func TestManager_SubmoduleDiscoveryStopsAtDepthLimit(t *testing.T) {
parent, parentCleanup := setupTestRepo(t)
t.Cleanup(parentCleanup)
mgr := NewManager(&config.InstanceConfig{WorkDir: parent}, newTestLogger(t))
t.Cleanup(mgr.stopWorkspaceTrackers)
got := mgr.discoverSubmoduleTrackers(
context.Background(),
mgr.GetWorkspaceTracker(),
nil,
parent,
maxSubmoduleDiscoveryDepth,
)
if got != nil {
t.Fatalf("depth-limited discovery returned %v trackers, want none", len(got))
}
}