repositories / bugabinga.net
bugabinga.net
personal infrastructure for bugabinga!
owned by admin
services/luci/internal/gitrepo/gitrepo_test.go
Rawpackage gitrepo
import (
"errors"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
func TestResolveAndCheckout(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "repo")
path, err := RepoPath([]string{root}, "repo")
if err != nil {
t.Fatalf("RepoPath() error = %v", err)
}
if path != bare {
t.Fatalf("RepoPath() = %q, want %q", path, bare)
}
rev, err := Resolve(path, "refs/heads/main", "")
if err != nil {
t.Fatalf("Resolve() error = %v", err)
}
workspace := filepath.Join(root, "workspace")
if err := os.MkdirAll(workspace, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(workspace, "stale"), []byte("old"), 0o644); err != nil {
t.Fatal(err)
}
if err := Checkout(path, rev, workspace); err != nil {
t.Fatalf("Checkout() error = %v", err)
}
data, err := os.ReadFile(filepath.Join(workspace, "README.md"))
if err != nil {
t.Fatalf("checked out file missing: %v", err)
}
if string(data) != "hello\n" {
t.Fatalf("README = %q", data)
}
if _, err := os.Stat(filepath.Join(workspace, "stale")); !os.IsNotExist(err) {
t.Fatalf("stale file survived: %v", err)
}
for _, check := range []struct {
args []string
want string
}{
{[]string{"rev-parse", "HEAD"}, rev},
{[]string{"rev-list", "--count", "HEAD"}, "1"},
{[]string{"remote"}, ""},
{[]string{"ls-files"}, "README.md"},
{[]string{"status", "--porcelain"}, ""},
} {
cmd := exec.Command("git", append([]string{"-C", workspace}, check.args...)...)
out, err := cmd.CombinedOutput()
if err != nil || strings.TrimSpace(string(out)) != check.want {
t.Fatalf("git %v = %q, %v; want %q", check.args, out, err, check.want)
}
}
}
func TestCheckoutKeepsBareRepoReadOnly(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "repo")
rev, err := Resolve(bare, "refs/heads/main", "")
if err != nil {
t.Fatal(err)
}
if err := os.Chmod(bare, 0o555); err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = os.Chmod(bare, 0o755) })
if err := Checkout(bare, rev, filepath.Join(root, "workspace")); err != nil {
t.Fatalf("Checkout() against read-only repo error = %v", err)
}
if _, err := os.Stat(filepath.Join(bare, "index")); !os.IsNotExist(err) {
t.Fatalf("checkout wrote bare repo index: %v", err)
}
}
func TestDefaultBranchAndChangedPaths(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "repo")
ref, first, err := DefaultBranch(bare)
if err != nil || ref != "refs/heads/main" || first == "" {
t.Fatalf("ref=%q rev=%q err=%v", ref, first, err)
}
all, err := ChangedPaths(bare, "0000000000000000000000000000000000000000", first)
if err != nil || len(all) != 1 || all[0] != "README.md" {
t.Fatalf("initial paths=%q err=%v", all, err)
}
work := filepath.Join(root, "work")
if err := os.MkdirAll(filepath.Join(work, "src", "nested"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(work, "src", "nested", "app.go"), []byte("package app\n"), 0o644); err != nil {
t.Fatal(err)
}
runGit(t, work, "add", ".")
runGit(t, work, "commit", "-m", "add source")
runGit(t, work, "remote", "add", "origin", bare)
runGit(t, work, "push", "origin", "main")
second, err := Resolve(bare, "refs/heads/main", "")
if err != nil {
t.Fatal(err)
}
changed, err := ChangedPaths(bare, first, second)
if err != nil || len(changed) != 1 || changed[0] != "src/nested/app.go" {
t.Fatalf("changed=%q err=%v", changed, err)
}
workspace := filepath.Join(root, "old-revision")
if err := Checkout(bare, first, workspace); err != nil {
t.Fatalf("Checkout() old revision error = %v", err)
}
if got := strings.TrimSpace(runGit(t, workspace, "rev-parse", "HEAD")); got != first {
t.Fatalf("old checkout HEAD = %q, want %q", got, first)
}
}
func TestChangedPathsRejectsOptionLikeRevisions(t *testing.T) {
if _, err := ChangedPaths(t.TempDir(), "--output=/tmp/x", strings.Repeat("a", 40)); err == nil {
t.Fatal("option-like old revision accepted")
}
if _, err := ChangedPaths(t.TempDir(), strings.Repeat("0", 40), "--help"); err == nil {
t.Fatal("option-like new revision accepted")
}
}
func TestResolvePrefersRevAndRejectsMissingRefOrBadRev(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "repo")
rev, err := Resolve(bare, "refs/heads/missing", "main")
if err != nil {
t.Fatalf("Resolve rev error = %v", err)
}
if rev == "" {
t.Fatal("empty rev")
}
if _, err := Resolve(bare, "", ""); err == nil {
t.Fatal("empty ref/rev accepted")
}
if _, err := Resolve(bare, "", "missing"); err == nil {
t.Fatal("bad rev accepted")
}
}
func TestCheckoutRejectsEmptyBadRevAndBadWorkspace(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "repo")
if err := Checkout(bare, "", filepath.Join(root, "workspace")); err == nil {
t.Fatal("empty rev checkout accepted")
}
if err := Checkout(bare, "missing", filepath.Join(root, "workspace")); err == nil {
t.Fatal("bad rev checkout accepted")
}
file := filepath.Join(root, "file")
if err := os.WriteFile(file, []byte("x"), 0o644); err != nil {
t.Fatal(err)
}
rev, err := Resolve(bare, "refs/heads/main", "")
if err != nil {
t.Fatal(err)
}
if err := Checkout(bare, rev, filepath.Join(file, "workspace")); err == nil {
t.Fatal("bad workspace accepted")
}
}
func TestCheckoutPropagatesMkdirFailure(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "repo")
rev, err := Resolve(bare, "refs/heads/main", "")
if err != nil {
t.Fatal(err)
}
boom := errors.New("boom")
old := mkdirAll
mkdirAll = func(string, os.FileMode) error { return boom }
defer func() { mkdirAll = old }()
if err := Checkout(bare, rev, filepath.Join(root, "workspace")); !errors.Is(err, boom) {
t.Fatalf("err = %v", err)
}
}
func TestRepoPathFindsPlainRepoDirAndRejectsMissing(t *testing.T) {
root := t.TempDir()
bare := createBareRepo(t, root, "plain")
plain := filepath.Join(root, "plain")
if err := os.Rename(bare, plain); err != nil {
t.Fatal(err)
}
path, err := RepoPath([]string{root}, "plain")
if err != nil {
t.Fatalf("RepoPath plain error = %v", err)
}
if path != plain {
t.Fatalf("path = %q, want %q", path, plain)
}
if _, err := RepoPath([]string{root}, "missing"); err == nil {
t.Fatal("missing repo accepted")
}
}
func TestRepoPathRejectsTraversal(t *testing.T) {
if _, err := RepoPath([]string{t.TempDir()}, "../repo"); err == nil {
t.Fatal("traversal repo accepted")
}
}
func createBareRepo(t *testing.T, root string, name string) string {
t.Helper()
work := filepath.Join(root, "work")
runGit(t, root, "init", work)
runGit(t, work, "config", "user.email", "test@example.invalid")
runGit(t, work, "config", "user.name", "Test")
if err := os.WriteFile(filepath.Join(work, "README.md"), []byte("hello\n"), 0o644); err != nil {
t.Fatal(err)
}
runGit(t, work, "add", "README.md")
runGit(t, work, "commit", "-m", "initial")
runGit(t, work, "branch", "-M", "main")
bare := filepath.Join(root, name+".git")
runGit(t, root, "clone", "--bare", work, bare)
return bare
}
func runGit(t *testing.T, dir string, args ...string) string {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %v failed: %v: %s", args, err, out)
}
return string(out)
}