0b349e2415
R-615: a changed git.repo_url was inert (the clone's stored origin was fetched for ever). The sync now compares the configured URL with the clone's origin: another repository -> drop the cache and clone it; the same repository with new credentials -> set-url. R-607: a catalog move that changed no stack directory (a deployed, pinned app keeps its stored definition) skipped the rescan, so CatalogImages and the update badge stayed stale, and the sync said 'nincs változás'. The sync now notes the cache commit before and after, rescans when it moved, says so, and returns catalog_moved. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
133 lines
4.1 KiB
Go
133 lines
4.1 KiB
Go
package sync
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/config"
|
|
)
|
|
|
|
// Local git repositories only (file://) — no network.
|
|
|
|
func gitT(t *testing.T, dir string, args ...string) string {
|
|
t.Helper()
|
|
cmd := exec.Command("git", append([]string{"-c", "user.email=t@example.invalid", "-c", "user.name=t", "-c", "init.defaultBranch=main", "-c", "commit.gpgsign=false"}, args...)...)
|
|
cmd.Dir = dir
|
|
out, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("git %v: %v\n%s", args, err, out)
|
|
}
|
|
return strings.TrimSpace(string(out))
|
|
}
|
|
|
|
// newCatalogRepo makes a work repo with one template and a marker file, on branch main.
|
|
func newCatalogRepo(t *testing.T, marker string) string {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
gitT(t, dir, "init", "-q", "-b", "main")
|
|
app := filepath.Join(dir, "templates", "demo")
|
|
if err := os.MkdirAll(app, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(app, "docker-compose.yml"), []byte("services:\n web:\n image: busybox:1\n"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "MARKER"), []byte(marker), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gitT(t, dir, "add", "-A")
|
|
gitT(t, dir, "commit", "-q", "-m", "init")
|
|
return dir
|
|
}
|
|
|
|
func newLocalSyncer(t *testing.T, repo string, rescans *int) *Syncer {
|
|
t.Helper()
|
|
root := t.TempDir()
|
|
cfg := &config.Config{}
|
|
cfg.Git.RepoURL = "file://" + repo
|
|
cfg.Git.Branch = "main"
|
|
cfg.Git.SyncInterval = "15m"
|
|
cfg.Paths.DataDir = filepath.Join(root, "data")
|
|
cfg.Paths.StacksDir = filepath.Join(root, "stacks")
|
|
if err := os.MkdirAll(cfg.Paths.StacksDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return New(cfg, log.New(os.Stderr, "", 0), func() error { *rescans++; return nil }, nil)
|
|
}
|
|
|
|
func syncNow(t *testing.T, s *Syncer) SyncResult {
|
|
t.Helper()
|
|
s.mu.Lock()
|
|
s.lastSync = time.Now().Add(-time.Hour) // past the debounce
|
|
s.mu.Unlock()
|
|
res := s.TriggerSync()
|
|
if !res.OK {
|
|
t.Fatalf("sync failed: %s", res.Message)
|
|
}
|
|
return res
|
|
}
|
|
|
|
// R-615: changing git.repo_url under an existing cache makes the next sync read the NEW repository.
|
|
func TestR615_ChangedRepoURLIsFollowed(t *testing.T) {
|
|
a := newCatalogRepo(t, "catalog-A")
|
|
b := newCatalogRepo(t, "catalog-B")
|
|
n := 0
|
|
s := newLocalSyncer(t, a, &n)
|
|
syncNow(t, s)
|
|
readMarker := func() string {
|
|
bs, err := os.ReadFile(filepath.Join(s.cacheDir, "MARKER"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return string(bs)
|
|
}
|
|
if readMarker() != "catalog-A" {
|
|
t.Fatalf("setup: cache should hold catalog A")
|
|
}
|
|
s.cfg.Git.RepoURL = "file://" + b // the operator repoints the box
|
|
syncNow(t, s)
|
|
if got := readMarker(); got != "catalog-B" {
|
|
t.Fatalf("R-615: after changing repo_url the cache still reads %q — the old repository is still being followed", got)
|
|
}
|
|
if origin := gitT(t, s.cacheDir, "config", "--get", "remote.origin.url"); origin != "file://"+b {
|
|
t.Errorf("the cache's origin must be the configured repository, got %q", origin)
|
|
}
|
|
}
|
|
|
|
// R-607: a catalog move that changes no stack directory still rescans (CatalogImages is read from the
|
|
// cache) and is not reported as „nincs változás".
|
|
func TestR607_CatalogMoveWithoutStackChangeRescansAndSaysSo(t *testing.T) {
|
|
a := newCatalogRepo(t, "v1")
|
|
n := 0
|
|
s := newLocalSyncer(t, a, &n)
|
|
syncNow(t, s)
|
|
before := n
|
|
|
|
// No change at all: honest „nincs változás", no rescan.
|
|
res := syncNow(t, s)
|
|
if res.CatalogMoved || !strings.Contains(res.Message, "nincs v") || n != before {
|
|
t.Fatalf("an unchanged catalog: moved=%v msg=%q rescans %d->%d", res.CatalogMoved, res.Message, before, n)
|
|
}
|
|
|
|
// The catalog moves in a file no stack dir copies.
|
|
if err := os.WriteFile(filepath.Join(a, "MARKER"), []byte("v2"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
gitT(t, a, "commit", "-q", "-am", "move")
|
|
res = syncNow(t, s)
|
|
if !res.CatalogMoved {
|
|
t.Fatal("R-607: the sync did not notice the catalog moved")
|
|
}
|
|
if n != before+1 {
|
|
t.Fatalf("R-607: a catalog move must rescan (CatalogImages is read from the cache); rescans %d->%d", before, n)
|
|
}
|
|
if strings.Contains(res.Message, "nincs v") {
|
|
t.Fatalf("R-607: a moved catalog was reported as unchanged: %q", res.Message)
|
|
}
|
|
}
|