Something went wrong. Try again.
Git backed by object storage because you can't stop me
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222package main
import ( "context" "net" "os" "os/exec" "path/filepath" "strings" "testing" "time"
"github.com/go-git/go-billy/v6" "github.com/go-git/go-billy/v6/memfs" "github.com/go-git/go-git/v6/plumbing/transport" "tangled.org/xeiaso.net/objgit/internal/auth")
// TestDaemonPushCreatesRepo reproduces "git push git://host/new.git" against a// path that does not exist yet. The daemon must create the bare repository on// demand and the result must clone back cleanly.func TestDaemonPushCreatesRepo(t *testing.T) { if _, err := exec.LookPath("git"); err != nil { t.Skip("git not installed") }
fs := memfs.New() d := &daemon{ fs: fs, loader: transport.NewFilesystemLoader(fs, false), authz: auth.AllowAnonymous{AllowWrite: true}, }
ctx, cancel := context.WithCancel(context.Background()) defer cancel()
ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listen: %v", err) }
srvErr := make(chan error, 1) go func() { srvErr <- d.Serve(ctx, ln) }()
remote := "git://" + ln.Addr().String() + "/test.git"
work := t.TempDir() runGit(t, work, "init", "-b", "main") runGit(t, work, "config", "user.email", "test@example.com") runGit(t, work, "config", "user.name", "Test") runGit(t, work, "commit", "--allow-empty", "-m", "initial")
// The repository does not exist yet; the push must create it. runGit(t, work, "push", remote, "main")
if _, err := fs.Stat("/test.git/config"); err != nil { t.Fatalf("expected bare repo to be created on push, but %q is missing: %v", "/test.git/config", err) }
// Round-trip: a clone must recover the pushed commit. dst := t.TempDir() runGit(t, dst, "clone", remote, "cloned") head := strings.TrimSpace(runGit(t, filepath.Join(dst, "cloned"), "rev-parse", "HEAD")) if head == "" { t.Fatal("cloned repository has no HEAD") }
cancel() _ = ln.Close() select { case <-srvErr: case <-time.After(2 * time.Second): t.Fatal("daemon did not shut down") }}
// TestDaemonPushDisabled confirms that pushes are rejected (not silently// creating repos) when allowPush is false.func TestDaemonPushDisabled(t *testing.T) { if _, err := exec.LookPath("git"); err != nil { t.Skip("git not installed") }
fs := memfs.New() d := &daemon{ fs: fs, loader: transport.NewFilesystemLoader(fs, false), authz: auth.AllowAnonymous{AllowWrite: false}, }
ctx, cancel := context.WithCancel(context.Background()) defer cancel()
ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listen: %v", err) } go func() { _ = d.Serve(ctx, ln) }()
remote := "git://" + ln.Addr().String() + "/test.git"
work := t.TempDir() runGit(t, work, "init", "-b", "main") runGit(t, work, "config", "user.email", "test@example.com") runGit(t, work, "config", "user.name", "Test") runGit(t, work, "commit", "--allow-empty", "-m", "initial")
if out, err := tryGit(work, "push", remote, "main"); err == nil { t.Fatalf("expected push to be rejected when allowPush is false, got success:\n%s", out) }
if _, err := fs.Stat("/test.git/config"); err == nil { t.Fatal("repository must not be created when push is disabled") }}
// TestDaemonPushKeepsPack verifies the receive-pack path stores the incoming// pack whole (objects/pack/pack-*.pack + .idx) rather than exploding it into// loose objects (objects/<2-hex>/...). git:// used to hide the PackfileWriter// capability and fall back to loose objects (one S3 PUT + one Lstat per object);// writePack now delimits the pack with a Scanner and feeds the PackfileWriter on// every transport.func TestDaemonPushKeepsPack(t *testing.T) { if _, err := exec.LookPath("git"); err != nil { t.Skip("git not installed") }
fs := memfs.New() d := &daemon{ fs: fs, loader: transport.NewFilesystemLoader(fs, false), authz: auth.AllowAnonymous{AllowWrite: true}, }
ctx, cancel := context.WithCancel(context.Background()) defer cancel()
ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("listen: %v", err) } go func() { _ = d.Serve(ctx, ln) }()
remote := "git://" + ln.Addr().String() + "/test.git"
work := t.TempDir() runGit(t, work, "init", "-b", "main") runGit(t, work, "config", "user.email", "test@example.com") runGit(t, work, "config", "user.name", "Test") writeFile(t, filepath.Join(work, "README.md"), "hello\n") runGit(t, work, "add", ".") runGit(t, work, "commit", "-m", "initial") // blob + tree + commit runGit(t, work, "push", remote, "main")
assertPackedRepo(t, fs, "/test.git")}
// assertPackedRepo fails unless repoPath holds at least one packfile and no loose// object directories (a 2-hex-char dir under objects/ such as "ab/").func assertPackedRepo(t *testing.T, fs billy.Filesystem, repoPath string) { t.Helper()
packs, err := fs.ReadDir(repoPath + "/objects/pack") if err != nil { t.Fatalf("ReadDir objects/pack: %v", err) } var packCount int for _, e := range packs { if strings.HasSuffix(e.Name(), ".pack") { packCount++ } } if packCount == 0 { t.Errorf("expected a packfile under %s/objects/pack, found none", repoPath) }
entries, err := fs.ReadDir(repoPath + "/objects") if err != nil { t.Fatalf("ReadDir objects: %v", err) } for _, e := range entries { if e.IsDir() && isLooseObjectDir(e.Name()) { t.Errorf("found loose-object dir objects/%s; pack should have been kept whole", e.Name()) } }}
// isLooseObjectDir reports whether name is a git loose-object fan-out directory// (two lowercase hex characters), distinguishing it from "pack" and "info".func isLooseObjectDir(name string) bool { if len(name) != 2 { return false } for _, c := range name { if !strings.ContainsRune("0123456789abcdef", c) { return false } } return true}
func runGit(t *testing.T, dir string, args ...string) string { t.Helper() out, err := tryGit(dir, args...) if err != nil { t.Fatalf("git %v: %v\n%s", args, err, out) } return out}
func tryGit(dir string, args ...string) (string, error) { cmd := exec.Command("git", args...) cmd.Dir = dir cmd.Env = append(os.Environ(), "GIT_CONFIG_GLOBAL=/dev/null", "GIT_CONFIG_SYSTEM=/dev/null", "GIT_TERMINAL_PROMPT=0", ) out, err := cmd.CombinedOutput() return string(out), err}