socle

test: end-to-end clone through a real listener

commit d095c08f9a8cbe60690bcc55f9a3df10964874f4 · parent 619b45eb15 · browse this tree
Ximianth, 2026-10-26 20:08:11 UTC

Three variants of an actual git clone against httptest: protocol v2 (the
modern default), forced v0 (which needs the "# service=" preamble), and
the .git-suffixed URL alias.  Checkout content and HEAD sha are asserted
against the fixture's pinned values.

One trap worth recording: the server must be torn down via t.Cleanup, not
defer, because parallel subtests outlive the parent function body (the
deferred Close otherwise lands before any clone starts).
diff --git a/clone_test.go b/clone_test.go
new file mode 100644
index 0000000..27ec4c4
--- /dev/null
+++ b/clone_test.go
@@ -0,0 +1,53 @@
+package main
+
+import (
+	"net/http/httptest"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+// TestCloneEndToEnd runs real `git clone`s against a real listener: the whole point
+// of the smart-HTTP endpoints, exercised by the actual client.
+// Variants cover protocol v2 (a modern client's default), forced v0 (the preamble path),
+// and the ".git"-suffixed URL alias.  The client runs under the same hermetic env
+// as fixture building, so no user config can steer its behavior.
+func TestCloneEndToEnd(t *testing.T) {
+	t.Parallel()
+	srv := httptest.NewServer(fixtureServer(t))
+	// Cleanup, not defer: the parallel subtests outlive this function body.
+	t.Cleanup(srv.Close)
+	for _, c := range []struct {
+		name    string
+		suffix  string
+		preArgs []string
+	}{
+		{name: "protocol v2", suffix: ""},
+		{name: "dot-git alias", suffix: ".git"},
+		{name: "protocol v0", preArgs: []string{"-c", "protocol.version=0"}},
+	} {
+		t.Run(c.name, func(t *testing.T) {
+			t.Parallel()
+			scratch := t.TempDir()
+			dest := filepath.Join(scratch, "clone")
+			args := append(c.preArgs, "clone", "-q", srv.URL+"/fixturama"+c.suffix, dest)
+			gitFixture(t, scratch, args...)
+
+			got, err := os.ReadFile(filepath.Join(dest, "README.md"))
+			if err != nil || string(got) != fixtureReadme {
+				t.Errorf("cloned README = %q, %v; want the fixture README", got, err)
+			}
+			cmd := exec.Command("git", "-C", dest, "rev-parse", "HEAD")
+			cmd.Env = append(os.Environ(), fixtureEnv...)
+			out, err := cmd.Output()
+			if err != nil {
+				t.Fatalf("rev-parse in clone: %v", err)
+			}
+			if sha := strings.TrimSpace(string(out)); sha != fixtureShaMain {
+				t.Errorf("cloned HEAD = %s, want %s", sha, fixtureShaMain)
+			}
+		})
+	}
+}