tarakan-client/internal/snapshot/snapshot_test.go
Maxfield Luke 58b29a7f84
Some checks failed
CI and releases / Test and vet (push) Failing after 1s
CI and releases / Build release binaries (push) Has been skipped
CI and releases / Publish GitHub release (push) Has been skipped
Initial commit on Forgejo
Fresh repository history for elektrine/tarakan-client hosted at
https://git.elektrine.com/elektrine/tarakan-client.
2026-07-29 04:56:36 -04:00

140 lines
4.3 KiB
Go

package snapshot
import (
"errors"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func TestCreatePinsCommitWithoutGitMetadataAndDetectsChanges(t *testing.T) {
repository := createTestRepository(t)
commit := gitOutput(t, repository, "rev-parse", "HEAD")
snapshot, err := Create(repository, commit)
if err != nil {
t.Fatal(err)
}
root := snapshot.Root
t.Cleanup(func() { _ = snapshot.Close() })
if _, err := os.Stat(filepath.Join(root, ".git")); !os.IsNotExist(err) {
t.Fatalf("snapshot retains Git metadata: %v", err)
}
changed, err := snapshot.Changed()
if err != nil || changed {
t.Fatalf("unchanged snapshot: changed=%v err=%v", changed, err)
}
if err := os.WriteFile(filepath.Join(root, "README.md"), []byte("changed\n"), 0o600); err != nil {
t.Fatal(err)
}
changed, err = snapshot.Changed()
if err != nil || !changed {
t.Fatalf("changed snapshot: changed=%v err=%v", changed, err)
}
if err := snapshot.Close(); err != nil {
t.Fatal(err)
}
if _, err := os.Stat(root); !os.IsNotExist(err) {
t.Fatalf("snapshot was not destroyed: %v", err)
}
}
func TestCreateRejectsUnavailableCommit(t *testing.T) {
repository := createTestRepository(t)
_, err := Create(repository, "dead000000000000000000000000000000000000")
if !errors.Is(err, ErrCommitUnavailable) {
t.Fatalf("error = %v", err)
}
}
func TestCreateNeutralizesExternalAndEscapingSymlinks(t *testing.T) {
repository := createTestRepository(t)
// Absolute external pointer (common "works on my Mac" vendor path).
if err := os.Symlink("/Users/someone/Desktop/secret", filepath.Join(repository, "external-abs")); err != nil {
t.Fatal(err)
}
// Relative path that escapes the tree.
if err := os.Symlink("../host-secret", filepath.Join(repository, "escape")); err != nil {
t.Fatal(err)
}
// Safe in-tree relative link must be kept.
if err := os.Symlink("README.md", filepath.Join(repository, "readme-link")); err != nil {
t.Fatal(err)
}
runGitTest(t, repository, "add", "external-abs", "escape", "readme-link")
runGitTest(t, repository, "-c", "user.name=Tarakan Test", "-c", "user.email=test@tarakan.invalid", "commit", "-m", "symlinks")
commit := gitOutput(t, repository, "rev-parse", "HEAD")
snap, err := Create(repository, commit)
if err != nil {
t.Fatalf("Create should neutralize external symlinks, got: %v", err)
}
t.Cleanup(func() { _ = snap.Close() })
// Escaping / absolute links become ordinary files with the original target.
for _, name := range []string{"external-abs", "escape"} {
info, err := os.Lstat(filepath.Join(snap.Root, name))
if err != nil {
t.Fatal(err)
}
if info.Mode()&os.ModeSymlink != 0 {
t.Fatalf("%s still a symlink", name)
}
body, err := os.ReadFile(filepath.Join(snap.Root, name))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(body), "neutralized external symlink") {
t.Fatalf("%s body = %q", name, body)
}
}
// In-tree relative symlink preserved.
target, err := os.Readlink(filepath.Join(snap.Root, "readme-link"))
if err != nil {
t.Fatalf("safe symlink should remain: %v", err)
}
if target != "README.md" {
t.Fatalf("safe symlink target = %q", target)
}
changed, err := snap.Changed()
if err != nil || changed {
t.Fatalf("unchanged after neutralize: changed=%v err=%v", changed, err)
}
}
func createTestRepository(t *testing.T) string {
t.Helper()
repository := t.TempDir()
runGitTest(t, repository, "init", "-b", "main")
if err := os.WriteFile(filepath.Join(repository, "README.md"), []byte("pinned\n"), 0o600); err != nil {
t.Fatal(err)
}
runGitTest(t, repository, "add", "README.md")
runGitTest(t, repository, "-c", "user.name=Tarakan Test", "-c", "user.email=test@tarakan.invalid", "commit", "-m", "initial")
return repository
}
func runGitTest(t *testing.T, directory string, arguments ...string) {
t.Helper()
command := exec.Command("git", append([]string{"-C", directory}, arguments...)...)
if output, err := command.CombinedOutput(); err != nil {
t.Fatalf("git %v: %v: %s", arguments, err, output)
}
}
func gitOutput(t *testing.T, directory string, arguments ...string) string {
t.Helper()
command := exec.Command("git", append([]string{"-C", directory}, arguments...)...)
output, err := command.Output()
if err != nil {
t.Fatalf("git %v: %v", arguments, err)
}
return strings.TrimSpace(string(output))
}